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