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 22CallgrindImageProfileResult::CallgrindImageProfileResult(SharedImage* image, 23 image_id id) 24 : 25 ImageProfileResult(image, id), 26 fFunctions(NULL), 27 fOutputIndex(0) 28{ 29} 30 31 32CallgrindImageProfileResult::~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 47status_t 48CallgrindImageProfileResult::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 61void 62CallgrindImageProfileResult::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 97CallgrindFunction* 98CallgrindImageProfileResult::Functions() const 99{ 100 return fFunctions; 101} 102 103 104int32 105CallgrindImageProfileResult::OutputIndex() const 106{ 107 return fOutputIndex; 108} 109 110 111void 112CallgrindImageProfileResult::SetOutputIndex(int32 index) 113{ 114 fOutputIndex = index; 115} 116 117 118// #pragma mark - CallgrindProfileResult 119 120 121CallgrindProfileResult::CallgrindProfileResult() 122 : 123 fTotalTicks(0), 124 fUnkownTicks(0), 125 fDroppedTicks(0), 126 fNextImageOutputIndex(1), 127 fNextFunctionOutputIndex(1) 128{ 129} 130 131 132void 133CallgrindProfileResult::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 166void 167CallgrindProfileResult::AddDroppedTicks(int32 dropped) 168{ 169 fDroppedTicks += dropped; 170} 171 172 173void 174CallgrindProfileResult::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 268status_t 269CallgrindProfileResult::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 288void 289CallgrindProfileResult::_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