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 "BasicProfileResult.h" 8 9 #if __GNUC__ > 2 10 #include <cxxabi.h> 11 #endif 12 #include <stdio.h> 13 14 #include <algorithm> 15 #include <new> 16 17 #include "Options.h" 18 #include "ProfiledEntity.h" 19 20 21 struct HitSymbol { 22 int64 hits; 23 Symbol* symbol; 24 image_id imageID; 25 26 inline bool operator<(const HitSymbol& other) const 27 { 28 return hits > other.hits; 29 } 30 }; 31 32 33 // #pragma mark - BasicImageProfileResult 34 35 36 BasicImageProfileResult::BasicImageProfileResult(SharedImage* image, 37 image_id id) 38 : 39 ImageProfileResult(image, id), 40 fSymbolHits(NULL), 41 fUnknownHits(0) 42 { 43 } 44 45 46 BasicImageProfileResult::~BasicImageProfileResult() 47 { 48 } 49 50 51 status_t 52 BasicImageProfileResult::Init() 53 { 54 int32 symbolCount = fImage->SymbolCount(); 55 fSymbolHits = new(std::nothrow) int64[symbolCount]; 56 if (fSymbolHits == NULL) 57 return B_NO_MEMORY; 58 59 memset(fSymbolHits, 0, 8 * symbolCount); 60 61 return B_OK; 62 } 63 64 65 bool 66 BasicImageProfileResult::AddHit(addr_t address) 67 { 68 int32 symbolIndex = fImage->FindSymbol(address); 69 if (symbolIndex < 0) 70 return false; 71 72 fSymbolHits[symbolIndex]++; 73 fTotalHits++; 74 75 return true; 76 } 77 78 79 void 80 BasicImageProfileResult::AddUnknownHit() 81 { 82 fUnknownHits++; 83 fTotalHits++; 84 } 85 86 87 void 88 BasicImageProfileResult::AddSymbolHit(int32 symbolIndex) 89 { 90 fSymbolHits[symbolIndex]++; 91 } 92 93 94 void 95 BasicImageProfileResult::AddImageHit() 96 { 97 fTotalHits++; 98 } 99 100 101 const int64* 102 BasicImageProfileResult::SymbolHits() const 103 { 104 return fSymbolHits; 105 } 106 107 108 int64 109 BasicImageProfileResult::UnknownHits() const 110 { 111 return fUnknownHits; 112 } 113 114 115 // #pragma mark - BasicProfileResult 116 117 118 BasicProfileResult::BasicProfileResult() 119 : 120 fTotalTicks(0), 121 fUnkownTicks(0), 122 fExpectedTicks(0), 123 fDroppedTicks(0), 124 fTotalSampleCount(0) 125 { 126 } 127 128 129 void 130 BasicProfileResult::AddExpectedTicks(int32 expected) 131 { 132 fExpectedTicks += expected; 133 } 134 135 136 void 137 BasicProfileResult::AddDroppedTicks(int32 dropped) 138 { 139 fDroppedTicks += dropped; 140 } 141 142 143 void 144 BasicProfileResult::PrintResults(ImageProfileResultContainer* container) 145 { 146 // get hit images 147 BasicImageProfileResult* images[container->CountImages()]; 148 int32 imageCount = GetHitImages(container, images); 149 150 // count symbols 151 int32 symbolCount = 0; 152 for (int32 k = 0; k < imageCount; k++) { 153 BasicImageProfileResult* image = images[k]; 154 if (image->TotalHits() > image->UnknownHits()) 155 symbolCount += image->GetImage()->SymbolCount(); 156 } 157 158 // find and sort the hit symbols 159 HitSymbol hitSymbols[symbolCount]; 160 int32 hitSymbolCount = 0; 161 162 for (int32 k = 0; k < imageCount; k++) { 163 BasicImageProfileResult* image = images[k]; 164 if (image->TotalHits() > image->UnknownHits()) { 165 Symbol** symbols = image->GetImage()->Symbols(); 166 const int64* symbolHits = image->SymbolHits(); 167 int32 imageSymbolCount = image->GetImage()->SymbolCount(); 168 for (int32 i = 0; i < imageSymbolCount; i++) { 169 if (symbolHits[i] > 0) { 170 HitSymbol& hitSymbol = hitSymbols[hitSymbolCount++]; 171 hitSymbol.hits = symbolHits[i]; 172 hitSymbol.symbol = symbols[i]; 173 hitSymbol.imageID = image->ID(); 174 } 175 } 176 } 177 } 178 179 if (hitSymbolCount > 1) 180 std::sort(hitSymbols, hitSymbols + hitSymbolCount); 181 182 int64 totalTicks = fTotalTicks; 183 const int64 missedTicks = fExpectedTicks - fTotalTicks; 184 185 fprintf(gOptions.output, "\nprofiling results for %s \"%s\" " 186 "(%" B_PRId32 "):\n", fEntity->EntityType(), fEntity->EntityName(), 187 fEntity->EntityID()); 188 fprintf(gOptions.output, " tick interval: %" B_PRIdBIGTIME " us\n", 189 fInterval); 190 fprintf(gOptions.output, 191 " total ticks: %" B_PRId64 " (%" B_PRId64 " us)\n", 192 totalTicks, totalTicks * fInterval); 193 if (fExpectedTicks != 0) { 194 fprintf(gOptions.output, 195 " expected ticks: %" B_PRId64 " (missed %" B_PRId64 ")\n", 196 fExpectedTicks, missedTicks); 197 } 198 if (totalTicks == 0) 199 totalTicks = 1; 200 201 fprintf(gOptions.output, 202 " unknown ticks: %" B_PRId64 " (%" B_PRId64 " us, %6.2f%%)\n", 203 fUnkownTicks, fUnkownTicks * fInterval, 204 100.0 * fUnkownTicks / totalTicks); 205 fprintf(gOptions.output, 206 " dropped ticks: %" B_PRId64 " (%" B_PRId64 " us, %6.2f%%)\n", 207 fDroppedTicks, fDroppedTicks * fInterval, 208 100.0 * fDroppedTicks / totalTicks); 209 if (gOptions.analyze_full_stack) { 210 fprintf(gOptions.output, " samples/tick: %.1f\n", 211 (double)fTotalSampleCount / totalTicks); 212 } 213 214 if (imageCount > 0) { 215 fprintf(gOptions.output, "\n"); 216 fprintf(gOptions.output, " hits unknown image\n"); 217 fprintf(gOptions.output, " ---------------------------------------" 218 "---------------------------------------\n"); 219 for (int32 k = 0; k < imageCount; k++) { 220 BasicImageProfileResult* image = images[k]; 221 fprintf(gOptions.output, 222 " %10" B_PRId64 " %10" B_PRId64 " %7" B_PRId32 " %s\n", 223 image->TotalHits(), image->UnknownHits(), 224 image->ID(), image->GetImage()->Name()); 225 } 226 } 227 228 if (hitSymbolCount > 0) { 229 fprintf(gOptions.output, "\n"); 230 fprintf(gOptions.output, " hits in us in %% " 231 "image function\n"); 232 fprintf(gOptions.output, " ---------------------------------------" 233 "---------------------------------------\n"); 234 for (int32 i = 0; i < hitSymbolCount; i++) { 235 const HitSymbol& hitSymbol = hitSymbols[i]; 236 const Symbol* symbol = hitSymbol.symbol; 237 #if __GNUC__ > 2 238 int status; 239 const char* symbolName = __cxxabiv1::__cxa_demangle(symbol->Name(), 240 NULL, NULL, &status); 241 if (symbolName == NULL) 242 symbolName = symbol->Name(); 243 #else 244 const char* symbolName = symbol->Name(); 245 #endif 246 fprintf(gOptions.output, 247 " %10" B_PRId64 " %10" B_PRId64 " %6.2f %6" B_PRId32 248 " %s\n", hitSymbol.hits, hitSymbol.hits * fInterval, 249 100.0 * hitSymbol.hits / totalTicks, hitSymbol.imageID, 250 symbolName); 251 #if __GNUC__ > 2 252 if (status == 0) 253 free(const_cast<char*>(symbolName)); 254 #endif 255 } 256 } else 257 fprintf(gOptions.output, " no functions were hit\n"); 258 } 259 260 261 status_t 262 BasicProfileResult::GetImageProfileResult(SharedImage* image, image_id id, 263 ImageProfileResult*& _imageResult) 264 { 265 BasicImageProfileResult* result 266 = new(std::nothrow) BasicImageProfileResult(image, id); 267 if (result == NULL) 268 return B_NO_MEMORY; 269 270 status_t error = result->Init(); 271 if (error != B_OK) { 272 delete result; 273 return error; 274 } 275 276 _imageResult = result; 277 return B_OK; 278 } 279 280 281 // #pragma mark - InclusiveProfileResult 282 283 284 void 285 InclusiveProfileResult::AddSamples(ImageProfileResultContainer* container, 286 addr_t* samples, int32 sampleCount) 287 { 288 // Sort the samples. This way hits of the same symbol are 289 // successive and we can avoid incrementing the hit count of the 290 // same symbol twice. Same for images. 291 std::sort(samples, samples + sampleCount); 292 293 int32 unknownSamples = 0; 294 BasicImageProfileResult* previousImage = NULL; 295 int32 previousSymbol = -1; 296 297 for (int32 i = 0; i < sampleCount; i++) { 298 addr_t address = samples[i]; 299 addr_t loadDelta; 300 BasicImageProfileResult* image = static_cast<BasicImageProfileResult*>( 301 container->FindImage(address, loadDelta)); 302 int32 symbol = -1; 303 if (image != NULL) { 304 symbol = image->GetImage()->FindSymbol(address - loadDelta); 305 if (image != previousImage || symbol != previousSymbol) { 306 if (symbol < 0) 307 image->AddUnknownHit(); 308 else 309 image->AddSymbolHit(symbol); 310 } 311 312 if (image != previousImage) 313 image->AddImageHit(); 314 } else 315 unknownSamples++; 316 317 previousImage = image; 318 previousSymbol = symbol; 319 } 320 321 if (unknownSamples == sampleCount) 322 fUnkownTicks++; 323 324 fTotalTicks++; 325 fTotalSampleCount += sampleCount; 326 } 327 328 329 // #pragma mark - ExclusiveProfileResult 330 331 332 void 333 ExclusiveProfileResult::AddSamples(ImageProfileResultContainer* container, 334 addr_t* samples, int32 sampleCount) 335 { 336 BasicImageProfileResult* image = NULL; 337 // the image in which we hit a symbol 338 BasicImageProfileResult* firstImage = NULL; 339 // the first image we hit, != image if no symbol was hit 340 341 for (int32 k = 0; k < sampleCount; k++) { 342 addr_t address = samples[k]; 343 addr_t loadDelta; 344 image = static_cast<BasicImageProfileResult*>( 345 container->FindImage(address, loadDelta)); 346 if (image != NULL) { 347 if (image->AddHit(address - loadDelta)) 348 break; 349 if (firstImage == NULL) 350 firstImage = image; 351 } 352 } 353 354 if (image == NULL) { 355 if (firstImage != NULL) 356 firstImage->AddUnknownHit(); 357 else 358 fUnkownTicks++; 359 } 360 361 fTotalTicks++; 362 fTotalSampleCount += sampleCount; 363 } 364