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 fExpectedTicks(0), 126 fDroppedTicks(0), 127 fNextImageOutputIndex(1), 128 fNextFunctionOutputIndex(1) 129 { 130 } 131 132 133 void 134 CallgrindProfileResult::AddSamples(ImageProfileResultContainer* container, 135 addr_t* samples, int32 sampleCount) 136 { 137 int32 unknownSamples = 0; 138 CallgrindImageProfileResult* previousImage = NULL; 139 int32 previousSymbol = -1; 140 141 // TODO: That probably doesn't work with recursive functions. 142 for (int32 i = 0; i < sampleCount; i++) { 143 addr_t address = samples[i]; 144 addr_t loadDelta; 145 CallgrindImageProfileResult* image 146 = static_cast<CallgrindImageProfileResult*>( 147 container->FindImage(address, loadDelta)); 148 int32 symbol = -1; 149 if (image != NULL) { 150 symbol = image->GetImage()->FindSymbol(address - loadDelta); 151 if (symbol >= 0) { 152 image->AddSymbolHit(symbol, previousImage, previousSymbol); 153 previousImage = image; 154 previousSymbol = symbol; 155 } 156 } else 157 unknownSamples++; 158 } 159 160 if (unknownSamples == sampleCount) 161 fUnkownTicks++; 162 163 fTotalTicks++; 164 } 165 166 167 void 168 CallgrindProfileResult::AddExpectedTicks(int32 expected) 169 { 170 fExpectedTicks += expected; 171 } 172 173 174 void 175 CallgrindProfileResult::AddDroppedTicks(int32 dropped) 176 { 177 fDroppedTicks += dropped; 178 } 179 180 181 void 182 CallgrindProfileResult::PrintResults(ImageProfileResultContainer* container) 183 { 184 // create output file 185 186 // create output dir 187 mkdir(gOptions.callgrind_directory, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 188 189 // get the entity name and replace slashes by hyphens 190 char entityName[B_OS_NAME_LENGTH]; 191 strlcpy(entityName, fEntity->EntityName(), sizeof(entityName)); 192 char* slash = entityName; 193 while ((slash = strchr(slash, '/')) != NULL) 194 *slash = '-'; 195 196 // create the file name 197 char fileName[B_PATH_NAME_LENGTH]; 198 snprintf(fileName, sizeof(fileName), 199 "%s/callgrind.out.%" B_PRId32 ".%s.%" B_PRId64 "ms", 200 gOptions.callgrind_directory, fEntity->EntityID(), entityName, 201 fTotalTicks * fInterval); 202 203 // create the file 204 FILE* out = fopen(fileName, "w+"); 205 if (out == NULL) { 206 fprintf(stderr, "%s: Failed to open output file \"%s\": %s\n", 207 kCommandName, fileName, strerror(errno)); 208 return; 209 } 210 211 // write the header 212 fprintf(out, "version: 1\n"); 213 fprintf(out, "creator: Haiku profile\n"); 214 fprintf(out, "pid: %" B_PRId32 "\n", fEntity->EntityID()); 215 fprintf(out, "cmd: %s\n", fEntity->EntityName()); 216 fprintf(out, "part: 1\n\n"); 217 218 fprintf(out, "positions: line\n"); 219 fprintf(out, "events: Ticks Time\n"); 220 fprintf(out, "summary: %" B_PRId64 " %" B_PRId64 "\n", 221 fTotalTicks, fTotalTicks * fInterval); 222 223 // get hit images 224 CallgrindImageProfileResult* images[container->CountImages()]; 225 int32 imageCount = GetHitImages(container, images); 226 227 for (int32 i = 0; i < imageCount; i++) { 228 CallgrindImageProfileResult* image = images[i]; 229 230 CallgrindFunction* functions = image->Functions(); 231 int32 imageSymbolCount = image->GetImage()->SymbolCount(); 232 for (int32 k = 0; k < imageSymbolCount; k++) { 233 CallgrindFunction& function = functions[k]; 234 if (function.hits == 0 && function.calledFunctions == NULL) 235 continue; 236 237 fprintf(out, "\n"); 238 _PrintFunction(out, image, k, false); 239 fprintf(out, "0 %" B_PRId64 " %" B_PRId64 "\n", function.hits, 240 function.hits * fInterval); 241 242 CallgrindCalledFunction* calledFunction = function.calledFunctions; 243 while (calledFunction != NULL) { 244 _PrintFunction(out, calledFunction->image, 245 calledFunction->function, true); 246 fprintf(out, "calls=%" B_PRId64 " 0\n", calledFunction->hits); 247 fprintf(out, "0 %" B_PRId64 " %" B_PRId64 "\n", 248 calledFunction->hits, calledFunction->hits * fInterval); 249 calledFunction = calledFunction->next; 250 } 251 } 252 } 253 254 // print pseudo-functions for unknown and dropped ticks 255 if (fUnkownTicks + fDroppedTicks > 0) { 256 fprintf(out, "\nob=<pseudo>\n"); 257 258 if (fUnkownTicks > 0) { 259 fprintf(out, "\nfn=unknown\n"); 260 fprintf(out, "0 %" B_PRId64 "\n", fUnkownTicks); 261 } 262 263 if (fDroppedTicks > 0) { 264 fprintf(out, "\nfn=dropped\n"); 265 fprintf(out, "0 %" B_PRId64 "\n", fDroppedTicks); 266 } 267 } 268 269 fprintf(out, "\ntotals: %" B_PRId64 " %" B_PRId64 "\n", 270 fTotalTicks, fTotalTicks * fInterval); 271 272 fclose(out); 273 } 274 275 276 status_t 277 CallgrindProfileResult::GetImageProfileResult(SharedImage* image, image_id id, 278 ImageProfileResult*& _imageResult) 279 { 280 CallgrindImageProfileResult* result 281 = new(std::nothrow) CallgrindImageProfileResult(image, id); 282 if (result == NULL) 283 return B_NO_MEMORY; 284 285 status_t error = result->Init(); 286 if (error != B_OK) { 287 delete result; 288 return error; 289 } 290 291 _imageResult = result; 292 return B_OK; 293 } 294 295 296 void 297 CallgrindProfileResult::_PrintFunction(FILE* out, 298 CallgrindImageProfileResult* image, int32 functionIndex, bool called) 299 { 300 if (image->OutputIndex() == 0) { 301 // need to print the image name 302 int32 index = fNextImageOutputIndex++; 303 image->SetOutputIndex(index); 304 fprintf(out, 305 "%sob=(%" B_PRId32 ") %s:%" B_PRId32 "\n", called ? "c" : "", 306 index, image->GetImage()->Name(), image->ID()); 307 } else { 308 // image is already known 309 // TODO: We may not need to print it at all! 310 fprintf(out, 311 "%sob=(%" B_PRId32 ")\n", called ? "c" : "", image->OutputIndex()); 312 } 313 314 CallgrindFunction& function = image->Functions()[functionIndex]; 315 if (function.outputIndex == 0) { 316 // need to print the function name 317 function.outputIndex = fNextFunctionOutputIndex++; 318 fprintf(out, 319 "%sfn=(%" B_PRId32 ") %s\n", called ? "c" : "", 320 function.outputIndex, 321 image->GetImage()->Symbols()[functionIndex]->Name()); 322 } else { 323 // function is already known 324 fprintf(out, 325 "%sfn=(%" B_PRId32 ")\n", called ? "c" : "", function.outputIndex); 326 } 327 } 328