1 /* 2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "CallgrindProfileResult.h" 8 9 #include <errno.h> 10 #include <sys/stat.h> 11 12 #include <algorithm> 13 #include <new> 14 15 #include "Options.h" 16 #include "ProfiledEntity.h" 17 18 19 // #pragma mark - CallgrindImageProfileResult 20 21 22 CallgrindImageProfileResult::CallgrindImageProfileResult(SharedImage* image, 23 image_id id) 24 : 25 ImageProfileResult(image, id), 26 fFunctions(NULL), 27 fOutputIndex(0) 28 { 29 } 30 31 32 CallgrindImageProfileResult::~CallgrindImageProfileResult() 33 { 34 int32 symbolCount = fImage->SymbolCount(); 35 for (int32 i = 0; i < symbolCount; i++) { 36 while (CallgrindCalledFunction* calledFunction 37 = fFunctions[i].calledFunctions) { 38 fFunctions[i].calledFunctions = calledFunction->next; 39 delete calledFunction; 40 } 41 } 42 43 delete[] fFunctions; 44 } 45 46 47 status_t 48 CallgrindImageProfileResult::Init() 49 { 50 int32 symbolCount = fImage->SymbolCount(); 51 fFunctions = new(std::nothrow) CallgrindFunction[symbolCount]; 52 if (fFunctions == NULL) 53 return B_NO_MEMORY; 54 55 memset(fFunctions, 0, sizeof(CallgrindFunction) * symbolCount); 56 57 return B_OK; 58 } 59 60 61 void 62 CallgrindImageProfileResult::AddSymbolHit(int32 symbolIndex, 63 CallgrindImageProfileResult* calledImage, int32 calledSymbol) 64 65 { 66 fTotalHits++; 67 68 CallgrindFunction& function = fFunctions[symbolIndex]; 69 if (calledImage != NULL) { 70 // check whether the called function is known already 71 CallgrindCalledFunction* calledFunction = function.calledFunctions; 72 while (calledFunction != NULL) { 73 if (calledFunction->image == calledImage 74 && calledFunction->function == calledSymbol) { 75 break; 76 } 77 calledFunction = calledFunction->next; 78 } 79 80 // create a new CallgrindCalledFunction object, if not known 81 if (calledFunction == NULL) { 82 calledFunction = new(std::nothrow) CallgrindCalledFunction( 83 calledImage, calledSymbol); 84 if (calledFunction == NULL) 85 return; 86 87 calledFunction->next = function.calledFunctions; 88 function.calledFunctions = calledFunction; 89 } 90 91 calledFunction->hits++; 92 } else 93 function.hits++; 94 } 95 96 97 CallgrindFunction* 98 CallgrindImageProfileResult::Functions() const 99 { 100 return fFunctions; 101 } 102 103 104 int32 105 CallgrindImageProfileResult::OutputIndex() const 106 { 107 return fOutputIndex; 108 } 109 110 111 void 112 CallgrindImageProfileResult::SetOutputIndex(int32 index) 113 { 114 fOutputIndex = index; 115 } 116 117 118 // #pragma mark - CallgrindProfileResult 119 120 121 CallgrindProfileResult::CallgrindProfileResult() 122 : 123 fTotalTicks(0), 124 fUnkownTicks(0), 125 fDroppedTicks(0), 126 fNextImageOutputIndex(1), 127 fNextFunctionOutputIndex(1) 128 { 129 } 130 131 132 void 133 CallgrindProfileResult::AddSamples(ImageProfileResultContainer* container, 134 addr_t* samples, int32 sampleCount) 135 { 136 int32 unknownSamples = 0; 137 CallgrindImageProfileResult* previousImage = NULL; 138 int32 previousSymbol = -1; 139 140 // TODO: That probably doesn't work with recursive functions. 141 for (int32 i = 0; i < sampleCount; i++) { 142 addr_t address = samples[i]; 143 addr_t loadDelta; 144 CallgrindImageProfileResult* image 145 = static_cast<CallgrindImageProfileResult*>( 146 container->FindImage(address, loadDelta)); 147 int32 symbol = -1; 148 if (image != NULL) { 149 symbol = image->GetImage()->FindSymbol(address - loadDelta); 150 if (symbol >= 0) { 151 image->AddSymbolHit(symbol, previousImage, previousSymbol); 152 previousImage = image; 153 previousSymbol = symbol; 154 } 155 } else 156 unknownSamples++; 157 } 158 159 if (unknownSamples == sampleCount) 160 fUnkownTicks++; 161 162 fTotalTicks++; 163 } 164 165 166 void 167 CallgrindProfileResult::AddDroppedTicks(int32 dropped) 168 { 169 fDroppedTicks += dropped; 170 } 171 172 173 void 174 CallgrindProfileResult::PrintResults(ImageProfileResultContainer* container) 175 { 176 // create output file 177 178 // create output dir 179 mkdir(gOptions.callgrind_directory, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 180 181 // get the entity name and replace slashes by hyphens 182 char entityName[B_OS_NAME_LENGTH]; 183 strlcpy(entityName, fEntity->EntityName(), sizeof(entityName)); 184 char* slash = entityName; 185 while ((slash = strchr(slash, '/')) != NULL) 186 *slash = '-'; 187 188 // create the file name 189 char fileName[B_PATH_NAME_LENGTH]; 190 snprintf(fileName, sizeof(fileName), 191 "%s/callgrind.out.%" B_PRId32 ".%s.%" B_PRId64 "ms", 192 gOptions.callgrind_directory, fEntity->EntityID(), entityName, 193 fTotalTicks * fInterval); 194 195 // create the file 196 FILE* out = fopen(fileName, "w+"); 197 if (out == NULL) { 198 fprintf(stderr, "%s: Failed to open output file \"%s\": %s\n", 199 kCommandName, fileName, strerror(errno)); 200 return; 201 } 202 203 // write the header 204 fprintf(out, "version: 1\n"); 205 fprintf(out, "creator: Haiku profile\n"); 206 fprintf(out, "pid: %" B_PRId32 "\n", fEntity->EntityID()); 207 fprintf(out, "cmd: %s\n", fEntity->EntityName()); 208 fprintf(out, "part: 1\n\n"); 209 210 fprintf(out, "positions: line\n"); 211 fprintf(out, "events: Ticks Time\n"); 212 fprintf(out, "summary: %" B_PRId64 " %" B_PRId64 "\n", 213 fTotalTicks, fTotalTicks * fInterval); 214 215 // get hit images 216 CallgrindImageProfileResult* images[container->CountImages()]; 217 int32 imageCount = GetHitImages(container, images); 218 219 for (int32 i = 0; i < imageCount; i++) { 220 CallgrindImageProfileResult* image = images[i]; 221 222 CallgrindFunction* functions = image->Functions(); 223 int32 imageSymbolCount = image->GetImage()->SymbolCount(); 224 for (int32 k = 0; k < imageSymbolCount; k++) { 225 CallgrindFunction& function = functions[k]; 226 if (function.hits == 0 && function.calledFunctions == NULL) 227 continue; 228 229 fprintf(out, "\n"); 230 _PrintFunction(out, image, k, false); 231 fprintf(out, "0 %" B_PRId64 " %" B_PRId64 "\n", function.hits, 232 function.hits * fInterval); 233 234 CallgrindCalledFunction* calledFunction = function.calledFunctions; 235 while (calledFunction != NULL) { 236 _PrintFunction(out, calledFunction->image, 237 calledFunction->function, true); 238 fprintf(out, "calls=%" B_PRId64 " 0\n", calledFunction->hits); 239 fprintf(out, "0 %" B_PRId64 " %" B_PRId64 "\n", 240 calledFunction->hits, calledFunction->hits * fInterval); 241 calledFunction = calledFunction->next; 242 } 243 } 244 } 245 246 // print pseudo-functions for unknown and dropped ticks 247 if (fUnkownTicks + fDroppedTicks > 0) { 248 fprintf(out, "\nob=<pseudo>\n"); 249 250 if (fUnkownTicks > 0) { 251 fprintf(out, "\nfn=unknown\n"); 252 fprintf(out, "0 %" B_PRId64 "\n", fUnkownTicks); 253 } 254 255 if (fDroppedTicks > 0) { 256 fprintf(out, "\nfn=dropped\n"); 257 fprintf(out, "0 %" B_PRId64 "\n", fDroppedTicks); 258 } 259 } 260 261 fprintf(out, "\ntotals: %" B_PRId64 " %" B_PRId64 "\n", 262 fTotalTicks, fTotalTicks * fInterval); 263 264 fclose(out); 265 } 266 267 268 status_t 269 CallgrindProfileResult::GetImageProfileResult(SharedImage* image, image_id id, 270 ImageProfileResult*& _imageResult) 271 { 272 CallgrindImageProfileResult* result 273 = new(std::nothrow) CallgrindImageProfileResult(image, id); 274 if (result == NULL) 275 return B_NO_MEMORY; 276 277 status_t error = result->Init(); 278 if (error != B_OK) { 279 delete result; 280 return error; 281 } 282 283 _imageResult = result; 284 return B_OK; 285 } 286 287 288 void 289 CallgrindProfileResult::_PrintFunction(FILE* out, 290 CallgrindImageProfileResult* image, int32 functionIndex, bool called) 291 { 292 if (image->OutputIndex() == 0) { 293 // need to print the image name 294 int32 index = fNextImageOutputIndex++; 295 image->SetOutputIndex(index); 296 fprintf(out, 297 "%sob=(%" B_PRId32 ") %s:%" B_PRId32 "\n", called ? "c" : "", 298 index, image->GetImage()->Name(), image->ID()); 299 } else { 300 // image is already known 301 // TODO: We may not need to print it at all! 302 fprintf(out, 303 "%sob=(%" B_PRId32 ")\n", called ? "c" : "", image->OutputIndex()); 304 } 305 306 CallgrindFunction& function = image->Functions()[functionIndex]; 307 if (function.outputIndex == 0) { 308 // need to print the function name 309 function.outputIndex = fNextFunctionOutputIndex++; 310 fprintf(out, 311 "%sfn=(%" B_PRId32 ") %s\n", called ? "c" : "", 312 function.outputIndex, 313 image->GetImage()->Symbols()[functionIndex]->Name()); 314 } else { 315 // function is already known 316 fprintf(out, 317 "%sfn=(%" B_PRId32 ")\n", called ? "c" : "", function.outputIndex); 318 } 319 } 320