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), "%s/callgrind.out.%ld.%s.%lldms", 191 gOptions.callgrind_directory, fEntity->EntityID(), entityName, 192 fTotalTicks * fInterval); 193 194 // create the file 195 FILE* out = fopen(fileName, "w+"); 196 if (out == NULL) { 197 fprintf(stderr, "%s: Failed to open output file \"%s\": %s\n", 198 kCommandName, fileName, strerror(errno)); 199 return; 200 } 201 202 // write the header 203 fprintf(out, "version: 1\n"); 204 fprintf(out, "creator: Haiku profile\n"); 205 fprintf(out, "pid: %ld\n", fEntity->EntityID()); 206 fprintf(out, "cmd: %s\n", fEntity->EntityName()); 207 fprintf(out, "part: 1\n\n"); 208 209 fprintf(out, "positions: line\n"); 210 fprintf(out, "events: Ticks Time\n"); 211 fprintf(out, "summary: %lld %lld\n", fTotalTicks, fTotalTicks * fInterval); 212 213 // get hit images 214 CallgrindImageProfileResult* images[container->CountImages()]; 215 int32 imageCount = GetHitImages(container, images); 216 217 for (int32 i = 0; i < imageCount; i++) { 218 CallgrindImageProfileResult* image = images[i]; 219 220 CallgrindFunction* functions = image->Functions(); 221 int32 imageSymbolCount = image->GetImage()->SymbolCount(); 222 for (int32 k = 0; k < imageSymbolCount; k++) { 223 CallgrindFunction& function = functions[k]; 224 if (function.hits == 0 && function.calledFunctions == NULL) 225 continue; 226 227 fprintf(out, "\n"); 228 _PrintFunction(out, image, k, false); 229 fprintf(out, "0 %lld %lld\n", function.hits, 230 function.hits * fInterval); 231 232 CallgrindCalledFunction* calledFunction = function.calledFunctions; 233 while (calledFunction != NULL) { 234 _PrintFunction(out, calledFunction->image, 235 calledFunction->function, true); 236 fprintf(out, "calls=%lld 0\n", calledFunction->hits); 237 fprintf(out, "0 %lld %lld\n", calledFunction->hits, 238 calledFunction->hits * fInterval); 239 calledFunction = calledFunction->next; 240 } 241 } 242 } 243 244 // print pseudo-functions for unknown and dropped ticks 245 if (fUnkownTicks + fDroppedTicks > 0) { 246 fprintf(out, "\nob=<pseudo>\n"); 247 248 if (fUnkownTicks > 0) { 249 fprintf(out, "\nfn=unknown\n"); 250 fprintf(out, "0 %lld\n", fUnkownTicks); 251 } 252 253 if (fDroppedTicks > 0) { 254 fprintf(out, "\nfn=dropped\n"); 255 fprintf(out, "0 %lld\n", fDroppedTicks); 256 } 257 } 258 259 fprintf(out, "\ntotals: %lld %lld\n", fTotalTicks, fTotalTicks * fInterval); 260 261 fclose(out); 262 } 263 264 265 status_t 266 CallgrindProfileResult::GetImageProfileResult(SharedImage* image, image_id id, 267 ImageProfileResult*& _imageResult) 268 { 269 CallgrindImageProfileResult* result 270 = new(std::nothrow) CallgrindImageProfileResult(image, id); 271 if (result == NULL) 272 return B_NO_MEMORY; 273 274 status_t error = result->Init(); 275 if (error != B_OK) { 276 delete result; 277 return error; 278 } 279 280 _imageResult = result; 281 return B_OK; 282 } 283 284 285 void 286 CallgrindProfileResult::_PrintFunction(FILE* out, 287 CallgrindImageProfileResult* image, int32 functionIndex, bool called) 288 { 289 if (image->OutputIndex() == 0) { 290 // need to print the image name 291 int32 index = fNextImageOutputIndex++; 292 image->SetOutputIndex(index); 293 fprintf(out, "%sob=(%ld) %s:%ld\n", called ? "c" : "", index, 294 image->GetImage()->Name(), image->ID()); 295 } else { 296 // image is already known 297 // TODO: We may not need to print it at all! 298 fprintf(out, "%sob=(%ld)\n", called ? "c" : "", image->OutputIndex()); 299 } 300 301 CallgrindFunction& function = image->Functions()[functionIndex]; 302 if (function.outputIndex == 0) { 303 // need to print the function name 304 function.outputIndex = fNextFunctionOutputIndex++; 305 fprintf(out, "%sfn=(%ld) %s\n", called ? "c" : "", function.outputIndex, 306 image->GetImage()->Symbols()[functionIndex]->Name()); 307 } else { 308 // function is already known 309 fprintf(out, "%sfn=(%ld)\n", called ? "c" : "", function.outputIndex); 310 } 311 } 312