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