1 //===-- ProfileGenerator.cpp - Profile Generator ---------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #include "ProfileGenerator.h" 9 #include "ErrorHandling.h" 10 #include "PerfReader.h" 11 #include "ProfiledBinary.h" 12 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" 13 #include "llvm/ProfileData/ProfileCommon.h" 14 #include <algorithm> 15 #include <float.h> 16 #include <unordered_set> 17 #include <utility> 18 19 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), 20 cl::Required, 21 cl::desc("Output profile file")); 22 static cl::alias OutputA("o", cl::desc("Alias for --output"), 23 cl::aliasopt(OutputFilename)); 24 25 static cl::opt<SampleProfileFormat> OutputFormat( 26 "format", cl::desc("Format of output profile"), cl::init(SPF_Ext_Binary), 27 cl::values( 28 clEnumValN(SPF_Binary, "binary", "Binary encoding (default)"), 29 clEnumValN(SPF_Compact_Binary, "compbinary", "Compact binary encoding"), 30 clEnumValN(SPF_Ext_Binary, "extbinary", "Extensible binary encoding"), 31 clEnumValN(SPF_Text, "text", "Text encoding"), 32 clEnumValN(SPF_GCC, "gcc", 33 "GCC encoding (only meaningful for -sample)"))); 34 35 cl::opt<bool> UseMD5( 36 "use-md5", cl::init(false), cl::Hidden, 37 cl::desc("Use md5 to represent function names in the output profile (only " 38 "meaningful for -extbinary)")); 39 40 static cl::opt<bool> PopulateProfileSymbolList( 41 "populate-profile-symbol-list", cl::init(false), cl::Hidden, 42 cl::desc("Populate profile symbol list (only meaningful for -extbinary)")); 43 44 static cl::opt<bool> FillZeroForAllFuncs( 45 "fill-zero-for-all-funcs", cl::init(false), cl::Hidden, 46 cl::desc("Attribute all functions' range with zero count " 47 "even it's not hit by any samples.")); 48 49 static cl::opt<int32_t, true> RecursionCompression( 50 "compress-recursion", 51 cl::desc("Compressing recursion by deduplicating adjacent frame " 52 "sequences up to the specified size. -1 means no size limit."), 53 cl::Hidden, 54 cl::location(llvm::sampleprof::CSProfileGenerator::MaxCompressionSize)); 55 56 static cl::opt<bool> 57 TrimColdProfile("trim-cold-profile", cl::init(false), cl::ZeroOrMore, 58 cl::desc("If the total count of the profile is smaller " 59 "than threshold, it will be trimmed.")); 60 61 static cl::opt<bool> CSProfMergeColdContext( 62 "csprof-merge-cold-context", cl::init(true), cl::ZeroOrMore, 63 cl::desc("If the total count of context profile is smaller than " 64 "the threshold, it will be merged into context-less base " 65 "profile.")); 66 67 static cl::opt<uint32_t> CSProfMaxColdContextDepth( 68 "csprof-max-cold-context-depth", cl::init(1), cl::ZeroOrMore, 69 cl::desc("Keep the last K contexts while merging cold profile. 1 means the " 70 "context-less base profile")); 71 72 static cl::opt<int, true> CSProfMaxContextDepth( 73 "csprof-max-context-depth", cl::ZeroOrMore, 74 cl::desc("Keep the last K contexts while merging profile. -1 means no " 75 "depth limit."), 76 cl::location(llvm::sampleprof::CSProfileGenerator::MaxContextDepth)); 77 78 static cl::opt<double> HotFunctionDensityThreshold( 79 "hot-function-density-threshold", llvm::cl::init(1000), 80 llvm::cl::desc( 81 "specify density threshold for hot functions (default: 1000)"), 82 llvm::cl::Optional); 83 static cl::opt<bool> ShowDensity("show-density", llvm::cl::init(false), 84 llvm::cl::desc("show profile density details"), 85 llvm::cl::Optional); 86 87 static cl::opt<bool> UpdateTotalSamples( 88 "update-total-samples", llvm::cl::init(false), 89 llvm::cl::desc( 90 "Update total samples by accumulating all its body samples."), 91 llvm::cl::Optional); 92 93 extern cl::opt<int> ProfileSummaryCutoffHot; 94 95 static cl::opt<bool> GenCSNestedProfile( 96 "gen-cs-nested-profile", cl::Hidden, cl::init(true), 97 cl::desc("Generate nested function profiles for CSSPGO")); 98 99 using namespace llvm; 100 using namespace sampleprof; 101 102 namespace llvm { 103 namespace sampleprof { 104 105 // Initialize the MaxCompressionSize to -1 which means no size limit 106 int32_t CSProfileGenerator::MaxCompressionSize = -1; 107 108 int CSProfileGenerator::MaxContextDepth = -1; 109 110 bool ProfileGeneratorBase::UseFSDiscriminator = false; 111 112 std::unique_ptr<ProfileGeneratorBase> 113 ProfileGeneratorBase::create(ProfiledBinary *Binary, 114 const ContextSampleCounterMap *SampleCounters, 115 bool ProfileIsCSFlat) { 116 std::unique_ptr<ProfileGeneratorBase> Generator; 117 if (ProfileIsCSFlat) { 118 if (Binary->useFSDiscriminator()) 119 exitWithError("FS discriminator is not supported in CS profile."); 120 Generator.reset(new CSProfileGenerator(Binary, SampleCounters)); 121 } else { 122 Generator.reset(new ProfileGenerator(Binary, SampleCounters)); 123 } 124 ProfileGeneratorBase::UseFSDiscriminator = Binary->useFSDiscriminator(); 125 FunctionSamples::ProfileIsFS = Binary->useFSDiscriminator(); 126 127 return Generator; 128 } 129 130 std::unique_ptr<ProfileGeneratorBase> 131 ProfileGeneratorBase::create(ProfiledBinary *Binary, 132 const SampleProfileMap &&Profiles, 133 bool ProfileIsCSFlat) { 134 std::unique_ptr<ProfileGeneratorBase> Generator; 135 if (ProfileIsCSFlat) { 136 if (Binary->useFSDiscriminator()) 137 exitWithError("FS discriminator is not supported in CS profile."); 138 Generator.reset(new CSProfileGenerator(Binary, std::move(Profiles))); 139 } else { 140 Generator.reset(new ProfileGenerator(Binary, std::move(Profiles))); 141 } 142 ProfileGeneratorBase::UseFSDiscriminator = Binary->useFSDiscriminator(); 143 FunctionSamples::ProfileIsFS = Binary->useFSDiscriminator(); 144 145 return Generator; 146 } 147 148 void ProfileGeneratorBase::write(std::unique_ptr<SampleProfileWriter> Writer, 149 SampleProfileMap &ProfileMap) { 150 // Populate profile symbol list if extended binary format is used. 151 ProfileSymbolList SymbolList; 152 153 if (PopulateProfileSymbolList && OutputFormat == SPF_Ext_Binary) { 154 Binary->populateSymbolListFromDWARF(SymbolList); 155 Writer->setProfileSymbolList(&SymbolList); 156 } 157 158 if (std::error_code EC = Writer->write(ProfileMap)) 159 exitWithError(std::move(EC)); 160 } 161 162 void ProfileGeneratorBase::write() { 163 auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat); 164 if (std::error_code EC = WriterOrErr.getError()) 165 exitWithError(EC, OutputFilename); 166 167 if (UseMD5) { 168 if (OutputFormat != SPF_Ext_Binary) 169 WithColor::warning() << "-use-md5 is ignored. Specify " 170 "--format=extbinary to enable it\n"; 171 else 172 WriterOrErr.get()->setUseMD5(); 173 } 174 175 write(std::move(WriterOrErr.get()), ProfileMap); 176 } 177 178 void ProfileGeneratorBase::showDensitySuggestion(double Density) { 179 if (Density == 0.0) 180 WithColor::warning() << "The --profile-summary-cutoff-hot option may be " 181 "set too low. Please check your command.\n"; 182 else if (Density < HotFunctionDensityThreshold) 183 WithColor::warning() 184 << "AutoFDO is estimated to optimize better with " 185 << format("%.1f", HotFunctionDensityThreshold / Density) 186 << "x more samples. Please consider increasing sampling rate or " 187 "profiling for longer duration to get more samples.\n"; 188 189 if (ShowDensity) 190 outs() << "Minimum profile density for hot functions with top " 191 << format("%.2f", 192 static_cast<double>(ProfileSummaryCutoffHot.getValue()) / 193 10000) 194 << "% total samples: " << format("%.1f", Density) << "\n"; 195 } 196 197 double ProfileGeneratorBase::calculateDensity(const SampleProfileMap &Profiles, 198 uint64_t HotCntThreshold) { 199 double Density = DBL_MAX; 200 std::vector<const FunctionSamples *> HotFuncs; 201 for (auto &I : Profiles) { 202 auto &FuncSamples = I.second; 203 if (FuncSamples.getTotalSamples() < HotCntThreshold) 204 continue; 205 HotFuncs.emplace_back(&FuncSamples); 206 } 207 208 for (auto *FuncSamples : HotFuncs) { 209 auto *Func = Binary->getBinaryFunction(FuncSamples->getName()); 210 if (!Func) 211 continue; 212 uint64_t FuncSize = Func->getFuncSize(); 213 if (FuncSize == 0) 214 continue; 215 Density = 216 std::min(Density, static_cast<double>(FuncSamples->getTotalSamples()) / 217 FuncSize); 218 } 219 220 return Density == DBL_MAX ? 0.0 : Density; 221 } 222 223 void ProfileGeneratorBase::findDisjointRanges(RangeSample &DisjointRanges, 224 const RangeSample &Ranges) { 225 226 /* 227 Regions may overlap with each other. Using the boundary info, find all 228 disjoint ranges and their sample count. BoundaryPoint contains the count 229 multiple samples begin/end at this points. 230 231 |<--100-->| Sample1 232 |<------200------>| Sample2 233 A B C 234 235 In the example above, 236 Sample1 begins at A, ends at B, its value is 100. 237 Sample2 beings at A, ends at C, its value is 200. 238 For A, BeginCount is the sum of sample begins at A, which is 300 and no 239 samples ends at A, so EndCount is 0. 240 Then boundary points A, B, and C with begin/end counts are: 241 A: (300, 0) 242 B: (0, 100) 243 C: (0, 200) 244 */ 245 struct BoundaryPoint { 246 // Sum of sample counts beginning at this point 247 uint64_t BeginCount = UINT64_MAX; 248 // Sum of sample counts ending at this point 249 uint64_t EndCount = UINT64_MAX; 250 // Is the begin point of a zero range. 251 bool IsZeroRangeBegin = false; 252 // Is the end point of a zero range. 253 bool IsZeroRangeEnd = false; 254 255 void addBeginCount(uint64_t Count) { 256 if (BeginCount == UINT64_MAX) 257 BeginCount = 0; 258 BeginCount += Count; 259 } 260 261 void addEndCount(uint64_t Count) { 262 if (EndCount == UINT64_MAX) 263 EndCount = 0; 264 EndCount += Count; 265 } 266 }; 267 268 /* 269 For the above example. With boundary points, follwing logic finds two 270 disjoint region of 271 272 [A,B]: 300 273 [B+1,C]: 200 274 275 If there is a boundary point that both begin and end, the point itself 276 becomes a separate disjoint region. For example, if we have original 277 ranges of 278 279 |<--- 100 --->| 280 |<--- 200 --->| 281 A B C 282 283 there are three boundary points with their begin/end counts of 284 285 A: (100, 0) 286 B: (200, 100) 287 C: (0, 200) 288 289 the disjoint ranges would be 290 291 [A, B-1]: 100 292 [B, B]: 300 293 [B+1, C]: 200. 294 295 Example for zero value range: 296 297 |<--- 100 --->| 298 |<--- 200 --->| 299 |<--------------- 0 ----------------->| 300 A B C D E F 301 302 [A, B-1] : 0 303 [B, C] : 100 304 [C+1, D-1]: 0 305 [D, E] : 200 306 [E+1, F] : 0 307 */ 308 std::map<uint64_t, BoundaryPoint> Boundaries; 309 310 for (const auto &Item : Ranges) { 311 assert(Item.first.first <= Item.first.second && 312 "Invalid instruction range"); 313 auto &BeginPoint = Boundaries[Item.first.first]; 314 auto &EndPoint = Boundaries[Item.first.second]; 315 uint64_t Count = Item.second; 316 317 BeginPoint.addBeginCount(Count); 318 EndPoint.addEndCount(Count); 319 if (Count == 0) { 320 BeginPoint.IsZeroRangeBegin = true; 321 EndPoint.IsZeroRangeEnd = true; 322 } 323 } 324 325 // Use UINT64_MAX to indicate there is no existing range between BeginAddress 326 // and the next valid address 327 uint64_t BeginAddress = UINT64_MAX; 328 int ZeroRangeDepth = 0; 329 uint64_t Count = 0; 330 for (const auto &Item : Boundaries) { 331 uint64_t Address = Item.first; 332 const BoundaryPoint &Point = Item.second; 333 if (Point.BeginCount != UINT64_MAX) { 334 if (BeginAddress != UINT64_MAX) 335 DisjointRanges[{BeginAddress, Address - 1}] = Count; 336 Count += Point.BeginCount; 337 BeginAddress = Address; 338 ZeroRangeDepth += Point.IsZeroRangeBegin; 339 } 340 if (Point.EndCount != UINT64_MAX) { 341 assert((BeginAddress != UINT64_MAX) && 342 "First boundary point cannot be 'end' point"); 343 DisjointRanges[{BeginAddress, Address}] = Count; 344 assert(Count >= Point.EndCount && "Mismatched live ranges"); 345 Count -= Point.EndCount; 346 BeginAddress = Address + 1; 347 ZeroRangeDepth -= Point.IsZeroRangeEnd; 348 // If the remaining count is zero and it's no longer in a zero range, this 349 // means we consume all the ranges before, thus mark BeginAddress as 350 // UINT64_MAX. e.g. supposing we have two non-overlapping ranges: 351 // [<---- 10 ---->] 352 // [<---- 20 ---->] 353 // A B C D 354 // The BeginAddress(B+1) will reset to invalid(UINT64_MAX), so we won't 355 // have the [B+1, C-1] zero range. 356 if (Count == 0 && ZeroRangeDepth == 0) 357 BeginAddress = UINT64_MAX; 358 } 359 } 360 } 361 362 void ProfileGeneratorBase::updateBodySamplesforFunctionProfile( 363 FunctionSamples &FunctionProfile, const SampleContextFrame &LeafLoc, 364 uint64_t Count) { 365 // Use the maximum count of samples with same line location 366 uint32_t Discriminator = getBaseDiscriminator(LeafLoc.Location.Discriminator); 367 368 // Use duplication factor to compensated for loop unroll/vectorization. 369 // Note that this is only needed when we're taking MAX of the counts at 370 // the location instead of SUM. 371 Count *= getDuplicationFactor(LeafLoc.Location.Discriminator); 372 373 ErrorOr<uint64_t> R = 374 FunctionProfile.findSamplesAt(LeafLoc.Location.LineOffset, Discriminator); 375 376 uint64_t PreviousCount = R ? R.get() : 0; 377 if (PreviousCount <= Count) { 378 FunctionProfile.addBodySamples(LeafLoc.Location.LineOffset, Discriminator, 379 Count - PreviousCount); 380 } 381 } 382 383 void ProfileGeneratorBase::updateTotalSamples() { 384 if (!UpdateTotalSamples) 385 return; 386 387 for (auto &Item : ProfileMap) { 388 FunctionSamples &FunctionProfile = Item.second; 389 FunctionProfile.updateTotalSamples(); 390 } 391 } 392 393 void ProfileGeneratorBase::collectProfiledFunctions() { 394 std::unordered_set<const BinaryFunction *> ProfiledFunctions; 395 if (SampleCounters) { 396 // Go through all the stacks, ranges and branches in sample counters, use 397 // the start of the range to look up the function it belongs and record the 398 // function. 399 for (const auto &CI : *SampleCounters) { 400 if (const auto *CtxKey = dyn_cast<AddrBasedCtxKey>(CI.first.getPtr())) { 401 for (auto Addr : CtxKey->Context) { 402 if (FuncRange *FRange = Binary->findFuncRangeForOffset( 403 Binary->virtualAddrToOffset(Addr))) 404 ProfiledFunctions.insert(FRange->Func); 405 } 406 } 407 408 for (auto Item : CI.second.RangeCounter) { 409 uint64_t StartOffset = Item.first.first; 410 if (FuncRange *FRange = Binary->findFuncRangeForOffset(StartOffset)) 411 ProfiledFunctions.insert(FRange->Func); 412 } 413 414 for (auto Item : CI.second.BranchCounter) { 415 uint64_t SourceOffset = Item.first.first; 416 uint64_t TargetOffset = Item.first.first; 417 if (FuncRange *FRange = Binary->findFuncRangeForOffset(SourceOffset)) 418 ProfiledFunctions.insert(FRange->Func); 419 if (FuncRange *FRange = Binary->findFuncRangeForOffset(TargetOffset)) 420 ProfiledFunctions.insert(FRange->Func); 421 } 422 } 423 } else { 424 // This is for the case the input is a llvm sample profile. 425 for (const auto &FS : ProfileMap) { 426 if (auto *Func = Binary->getBinaryFunction(FS.first.getName())) 427 ProfiledFunctions.insert(Func); 428 } 429 } 430 431 Binary->setProfiledFunctions(ProfiledFunctions); 432 } 433 434 FunctionSamples & 435 ProfileGenerator::getTopLevelFunctionProfile(StringRef FuncName) { 436 SampleContext Context(FuncName); 437 auto Ret = ProfileMap.emplace(Context, FunctionSamples()); 438 if (Ret.second) { 439 FunctionSamples &FProfile = Ret.first->second; 440 FProfile.setContext(Context); 441 } 442 return Ret.first->second; 443 } 444 445 void ProfileGenerator::generateProfile() { 446 collectProfiledFunctions(); 447 448 if (Binary->usePseudoProbes()) 449 Binary->decodePseudoProbe(); 450 451 if (SampleCounters) { 452 if (Binary->usePseudoProbes()) { 453 generateProbeBasedProfile(); 454 } else { 455 generateLineNumBasedProfile(); 456 } 457 } 458 459 postProcessProfiles(); 460 } 461 462 void ProfileGenerator::postProcessProfiles() { 463 computeSummaryAndThreshold(); 464 trimColdProfiles(ProfileMap, ColdCountThreshold); 465 calculateAndShowDensity(ProfileMap); 466 } 467 468 void ProfileGenerator::trimColdProfiles(const SampleProfileMap &Profiles, 469 uint64_t ColdCntThreshold) { 470 if (!TrimColdProfile) 471 return; 472 473 // Move cold profiles into a tmp container. 474 std::vector<SampleContext> ColdProfiles; 475 for (const auto &I : ProfileMap) { 476 if (I.second.getTotalSamples() < ColdCntThreshold) 477 ColdProfiles.emplace_back(I.first); 478 } 479 480 // Remove the cold profile from ProfileMap. 481 for (const auto &I : ColdProfiles) 482 ProfileMap.erase(I); 483 } 484 485 void ProfileGenerator::generateLineNumBasedProfile() { 486 assert(SampleCounters->size() == 1 && 487 "Must have one entry for profile generation."); 488 const SampleCounter &SC = SampleCounters->begin()->second; 489 // Fill in function body samples 490 populateBodySamplesForAllFunctions(SC.RangeCounter); 491 // Fill in boundary sample counts as well as call site samples for calls 492 populateBoundarySamplesForAllFunctions(SC.BranchCounter); 493 494 updateTotalSamples(); 495 } 496 497 void ProfileGenerator::generateProbeBasedProfile() { 498 assert(SampleCounters->size() == 1 && 499 "Must have one entry for profile generation."); 500 // Enable pseudo probe functionalities in SampleProf 501 FunctionSamples::ProfileIsProbeBased = true; 502 const SampleCounter &SC = SampleCounters->begin()->second; 503 // Fill in function body samples 504 populateBodySamplesWithProbesForAllFunctions(SC.RangeCounter); 505 // Fill in boundary sample counts as well as call site samples for calls 506 populateBoundarySamplesWithProbesForAllFunctions(SC.BranchCounter); 507 508 updateTotalSamples(); 509 } 510 511 void ProfileGenerator::populateBodySamplesWithProbesForAllFunctions( 512 const RangeSample &RangeCounter) { 513 ProbeCounterMap ProbeCounter; 514 // preprocessRangeCounter returns disjoint ranges, so no longer to redo it 515 // inside extractProbesFromRange. 516 extractProbesFromRange(preprocessRangeCounter(RangeCounter), ProbeCounter, 517 false); 518 519 for (const auto &PI : ProbeCounter) { 520 const MCDecodedPseudoProbe *Probe = PI.first; 521 uint64_t Count = PI.second; 522 SampleContextFrameVector FrameVec; 523 Binary->getInlineContextForProbe(Probe, FrameVec, true); 524 FunctionSamples &FunctionProfile = 525 getLeafProfileAndAddTotalSamples(FrameVec, Count); 526 FunctionProfile.addBodySamplesForProbe(Probe->getIndex(), Count); 527 if (Probe->isEntry()) 528 FunctionProfile.addHeadSamples(Count); 529 } 530 } 531 532 void ProfileGenerator::populateBoundarySamplesWithProbesForAllFunctions( 533 const BranchSample &BranchCounters) { 534 for (const auto &Entry : BranchCounters) { 535 uint64_t SourceOffset = Entry.first.first; 536 uint64_t TargetOffset = Entry.first.second; 537 uint64_t Count = Entry.second; 538 assert(Count != 0 && "Unexpected zero weight branch"); 539 540 StringRef CalleeName = getCalleeNameForOffset(TargetOffset); 541 if (CalleeName.size() == 0) 542 continue; 543 544 uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset); 545 const MCDecodedPseudoProbe *CallProbe = 546 Binary->getCallProbeForAddr(SourceAddress); 547 if (CallProbe == nullptr) 548 continue; 549 550 // Record called target sample and its count. 551 SampleContextFrameVector FrameVec; 552 Binary->getInlineContextForProbe(CallProbe, FrameVec, true); 553 554 if (!FrameVec.empty()) { 555 FunctionSamples &FunctionProfile = 556 getLeafProfileAndAddTotalSamples(FrameVec, 0); 557 FunctionProfile.addCalledTargetSamples( 558 FrameVec.back().Location.LineOffset, 0, CalleeName, Count); 559 } 560 } 561 } 562 563 FunctionSamples &ProfileGenerator::getLeafProfileAndAddTotalSamples( 564 const SampleContextFrameVector &FrameVec, uint64_t Count) { 565 // Get top level profile 566 FunctionSamples *FunctionProfile = 567 &getTopLevelFunctionProfile(FrameVec[0].FuncName); 568 FunctionProfile->addTotalSamples(Count); 569 if (Binary->usePseudoProbes()) { 570 const auto *FuncDesc = Binary->getFuncDescForGUID( 571 Function::getGUID(FunctionProfile->getName())); 572 FunctionProfile->setFunctionHash(FuncDesc->FuncHash); 573 } 574 575 for (size_t I = 1; I < FrameVec.size(); I++) { 576 LineLocation Callsite( 577 FrameVec[I - 1].Location.LineOffset, 578 getBaseDiscriminator(FrameVec[I - 1].Location.Discriminator)); 579 FunctionSamplesMap &SamplesMap = 580 FunctionProfile->functionSamplesAt(Callsite); 581 auto Ret = 582 SamplesMap.emplace(FrameVec[I].FuncName.str(), FunctionSamples()); 583 if (Ret.second) { 584 SampleContext Context(FrameVec[I].FuncName); 585 Ret.first->second.setContext(Context); 586 } 587 FunctionProfile = &Ret.first->second; 588 FunctionProfile->addTotalSamples(Count); 589 if (Binary->usePseudoProbes()) { 590 const auto *FuncDesc = Binary->getFuncDescForGUID( 591 Function::getGUID(FunctionProfile->getName())); 592 FunctionProfile->setFunctionHash(FuncDesc->FuncHash); 593 } 594 } 595 596 return *FunctionProfile; 597 } 598 599 RangeSample 600 ProfileGenerator::preprocessRangeCounter(const RangeSample &RangeCounter) { 601 RangeSample Ranges(RangeCounter.begin(), RangeCounter.end()); 602 if (FillZeroForAllFuncs) { 603 for (auto &FuncI : Binary->getAllBinaryFunctions()) { 604 for (auto &R : FuncI.second.Ranges) { 605 Ranges[{R.first, R.second - 1}] += 0; 606 } 607 } 608 } else { 609 // For each range, we search for all ranges of the function it belongs to 610 // and initialize it with zero count, so it remains zero if doesn't hit any 611 // samples. This is to be consistent with compiler that interpret zero count 612 // as unexecuted(cold). 613 for (const auto &I : RangeCounter) { 614 uint64_t StartOffset = I.first.first; 615 for (const auto &Range : Binary->getRangesForOffset(StartOffset)) 616 Ranges[{Range.first, Range.second - 1}] += 0; 617 } 618 } 619 RangeSample DisjointRanges; 620 findDisjointRanges(DisjointRanges, Ranges); 621 return DisjointRanges; 622 } 623 624 void ProfileGenerator::populateBodySamplesForAllFunctions( 625 const RangeSample &RangeCounter) { 626 for (const auto &Range : preprocessRangeCounter(RangeCounter)) { 627 uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first); 628 uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second); 629 uint64_t Count = Range.second; 630 631 InstructionPointer IP(Binary, RangeBegin, true); 632 // Disjoint ranges may have range in the middle of two instr, 633 // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range 634 // can be Addr1+1 to Addr2-1. We should ignore such range. 635 if (IP.Address > RangeEnd) 636 continue; 637 638 do { 639 uint64_t Offset = Binary->virtualAddrToOffset(IP.Address); 640 const SampleContextFrameVector &FrameVec = 641 Binary->getFrameLocationStack(Offset); 642 if (!FrameVec.empty()) { 643 // FIXME: As accumulating total count per instruction caused some 644 // regression, we changed to accumulate total count per byte as a 645 // workaround. Tuning hotness threshold on the compiler side might be 646 // necessary in the future. 647 FunctionSamples &FunctionProfile = getLeafProfileAndAddTotalSamples( 648 FrameVec, Count * Binary->getInstSize(Offset)); 649 updateBodySamplesforFunctionProfile(FunctionProfile, FrameVec.back(), 650 Count); 651 } 652 } while (IP.advance() && IP.Address <= RangeEnd); 653 } 654 } 655 656 StringRef ProfileGeneratorBase::getCalleeNameForOffset(uint64_t TargetOffset) { 657 // Get the function range by branch target if it's a call branch. 658 auto *FRange = Binary->findFuncRangeForStartOffset(TargetOffset); 659 660 // We won't accumulate sample count for a range whose start is not the real 661 // function entry such as outlined function or inner labels. 662 if (!FRange || !FRange->IsFuncEntry) 663 return StringRef(); 664 665 return FunctionSamples::getCanonicalFnName(FRange->getFuncName()); 666 } 667 668 void ProfileGenerator::populateBoundarySamplesForAllFunctions( 669 const BranchSample &BranchCounters) { 670 for (const auto &Entry : BranchCounters) { 671 uint64_t SourceOffset = Entry.first.first; 672 uint64_t TargetOffset = Entry.first.second; 673 uint64_t Count = Entry.second; 674 assert(Count != 0 && "Unexpected zero weight branch"); 675 676 StringRef CalleeName = getCalleeNameForOffset(TargetOffset); 677 if (CalleeName.size() == 0) 678 continue; 679 // Record called target sample and its count. 680 const SampleContextFrameVector &FrameVec = 681 Binary->getFrameLocationStack(SourceOffset); 682 if (!FrameVec.empty()) { 683 FunctionSamples &FunctionProfile = 684 getLeafProfileAndAddTotalSamples(FrameVec, 0); 685 FunctionProfile.addCalledTargetSamples( 686 FrameVec.back().Location.LineOffset, 687 getBaseDiscriminator(FrameVec.back().Location.Discriminator), 688 CalleeName, Count); 689 } 690 // Add head samples for callee. 691 FunctionSamples &CalleeProfile = getTopLevelFunctionProfile(CalleeName); 692 CalleeProfile.addHeadSamples(Count); 693 } 694 } 695 696 void ProfileGeneratorBase::calculateAndShowDensity( 697 const SampleProfileMap &Profiles) { 698 double Density = calculateDensity(Profiles, HotCountThreshold); 699 showDensitySuggestion(Density); 700 } 701 702 FunctionSamples &CSProfileGenerator::getFunctionProfileForContext( 703 const SampleContextFrameVector &Context, bool WasLeafInlined) { 704 auto I = ProfileMap.find(SampleContext(Context)); 705 if (I == ProfileMap.end()) { 706 // Save the new context for future references. 707 SampleContextFrames NewContext = *Contexts.insert(Context).first; 708 SampleContext FContext(NewContext, RawContext); 709 auto Ret = ProfileMap.emplace(FContext, FunctionSamples()); 710 if (WasLeafInlined) 711 FContext.setAttribute(ContextWasInlined); 712 FunctionSamples &FProfile = Ret.first->second; 713 FProfile.setContext(FContext); 714 return Ret.first->second; 715 } 716 return I->second; 717 } 718 719 void CSProfileGenerator::generateProfile() { 720 FunctionSamples::ProfileIsCSFlat = true; 721 722 collectProfiledFunctions(); 723 724 if (Binary->usePseudoProbes()) 725 Binary->decodePseudoProbe(); 726 727 if (SampleCounters) { 728 if (Binary->usePseudoProbes()) { 729 generateProbeBasedProfile(); 730 } else { 731 generateLineNumBasedProfile(); 732 } 733 } 734 735 if (Binary->getTrackFuncContextSize()) 736 computeSizeForProfiledFunctions(); 737 738 postProcessProfiles(); 739 } 740 741 void CSProfileGenerator::computeSizeForProfiledFunctions() { 742 std::unordered_set<const BinaryFunction *> ProfiledFunctions; 743 for (auto *Func : Binary->getProfiledFunctions()) 744 Binary->computeInlinedContextSizeForFunc(Func); 745 746 // Flush the symbolizer to save memory. 747 Binary->flushSymbolizer(); 748 } 749 750 void CSProfileGenerator::generateLineNumBasedProfile() { 751 for (const auto &CI : *SampleCounters) { 752 const auto *CtxKey = cast<StringBasedCtxKey>(CI.first.getPtr()); 753 754 // Get or create function profile for the range 755 FunctionSamples &FunctionProfile = 756 getFunctionProfileForContext(CtxKey->Context, CtxKey->WasLeafInlined); 757 758 // Fill in function body samples 759 populateBodySamplesForFunction(FunctionProfile, CI.second.RangeCounter); 760 // Fill in boundary sample counts as well as call site samples for calls 761 populateBoundarySamplesForFunction(CtxKey->Context, FunctionProfile, 762 CI.second.BranchCounter); 763 } 764 // Fill in call site value sample for inlined calls and also use context to 765 // infer missing samples. Since we don't have call count for inlined 766 // functions, we estimate it from inlinee's profile using the entry of the 767 // body sample. 768 populateInferredFunctionSamples(); 769 770 updateTotalSamples(); 771 } 772 773 void CSProfileGenerator::populateBodySamplesForFunction( 774 FunctionSamples &FunctionProfile, const RangeSample &RangeCounter) { 775 // Compute disjoint ranges first, so we can use MAX 776 // for calculating count for each location. 777 RangeSample Ranges; 778 findDisjointRanges(Ranges, RangeCounter); 779 for (const auto &Range : Ranges) { 780 uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first); 781 uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second); 782 uint64_t Count = Range.second; 783 // Disjoint ranges have introduce zero-filled gap that 784 // doesn't belong to current context, filter them out. 785 if (Count == 0) 786 continue; 787 788 InstructionPointer IP(Binary, RangeBegin, true); 789 // Disjoint ranges may have range in the middle of two instr, 790 // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range 791 // can be Addr1+1 to Addr2-1. We should ignore such range. 792 if (IP.Address > RangeEnd) 793 continue; 794 795 do { 796 uint64_t Offset = Binary->virtualAddrToOffset(IP.Address); 797 auto LeafLoc = Binary->getInlineLeafFrameLoc(Offset); 798 if (LeafLoc.hasValue()) { 799 // Recording body sample for this specific context 800 updateBodySamplesforFunctionProfile(FunctionProfile, *LeafLoc, Count); 801 FunctionProfile.addTotalSamples(Count); 802 } 803 } while (IP.advance() && IP.Address <= RangeEnd); 804 } 805 } 806 807 void CSProfileGenerator::populateBoundarySamplesForFunction( 808 SampleContextFrames ContextId, FunctionSamples &FunctionProfile, 809 const BranchSample &BranchCounters) { 810 811 for (const auto &Entry : BranchCounters) { 812 uint64_t SourceOffset = Entry.first.first; 813 uint64_t TargetOffset = Entry.first.second; 814 uint64_t Count = Entry.second; 815 assert(Count != 0 && "Unexpected zero weight branch"); 816 817 StringRef CalleeName = getCalleeNameForOffset(TargetOffset); 818 if (CalleeName.size() == 0) 819 continue; 820 821 // Record called target sample and its count 822 auto LeafLoc = Binary->getInlineLeafFrameLoc(SourceOffset); 823 if (!LeafLoc.hasValue()) 824 continue; 825 FunctionProfile.addCalledTargetSamples( 826 LeafLoc->Location.LineOffset, 827 getBaseDiscriminator(LeafLoc->Location.Discriminator), CalleeName, 828 Count); 829 830 // Record head sample for called target(callee) 831 SampleContextFrameVector CalleeCtx(ContextId.begin(), ContextId.end()); 832 assert(CalleeCtx.back().FuncName == LeafLoc->FuncName && 833 "Leaf function name doesn't match"); 834 CalleeCtx.back() = *LeafLoc; 835 CalleeCtx.emplace_back(CalleeName, LineLocation(0, 0)); 836 FunctionSamples &CalleeProfile = getFunctionProfileForContext(CalleeCtx); 837 CalleeProfile.addHeadSamples(Count); 838 } 839 } 840 841 static SampleContextFrame 842 getCallerContext(SampleContextFrames CalleeContext, 843 SampleContextFrameVector &CallerContext) { 844 assert(CalleeContext.size() > 1 && "Unexpected empty context"); 845 CalleeContext = CalleeContext.drop_back(); 846 CallerContext.assign(CalleeContext.begin(), CalleeContext.end()); 847 SampleContextFrame CallerFrame = CallerContext.back(); 848 CallerContext.back().Location = LineLocation(0, 0); 849 return CallerFrame; 850 } 851 852 void CSProfileGenerator::populateInferredFunctionSamples() { 853 for (const auto &Item : ProfileMap) { 854 const auto &CalleeContext = Item.first; 855 const FunctionSamples &CalleeProfile = Item.second; 856 857 // If we already have head sample counts, we must have value profile 858 // for call sites added already. Skip to avoid double counting. 859 if (CalleeProfile.getHeadSamples()) 860 continue; 861 // If we don't have context, nothing to do for caller's call site. 862 // This could happen for entry point function. 863 if (CalleeContext.isBaseContext()) 864 continue; 865 866 // Infer Caller's frame loc and context ID through string splitting 867 SampleContextFrameVector CallerContextId; 868 SampleContextFrame &&CallerLeafFrameLoc = 869 getCallerContext(CalleeContext.getContextFrames(), CallerContextId); 870 SampleContextFrames CallerContext(CallerContextId); 871 872 // It's possible that we haven't seen any sample directly in the caller, 873 // in which case CallerProfile will not exist. But we can't modify 874 // ProfileMap while iterating it. 875 // TODO: created function profile for those callers too 876 if (ProfileMap.find(CallerContext) == ProfileMap.end()) 877 continue; 878 FunctionSamples &CallerProfile = ProfileMap[CallerContext]; 879 880 // Since we don't have call count for inlined functions, we 881 // estimate it from inlinee's profile using entry body sample. 882 uint64_t EstimatedCallCount = CalleeProfile.getEntrySamples(); 883 // If we don't have samples with location, use 1 to indicate live. 884 if (!EstimatedCallCount && !CalleeProfile.getBodySamples().size()) 885 EstimatedCallCount = 1; 886 CallerProfile.addCalledTargetSamples( 887 CallerLeafFrameLoc.Location.LineOffset, 888 CallerLeafFrameLoc.Location.Discriminator, 889 CalleeProfile.getContext().getName(), EstimatedCallCount); 890 CallerProfile.addBodySamples(CallerLeafFrameLoc.Location.LineOffset, 891 CallerLeafFrameLoc.Location.Discriminator, 892 EstimatedCallCount); 893 CallerProfile.addTotalSamples(EstimatedCallCount); 894 } 895 } 896 897 void CSProfileGenerator::postProcessProfiles() { 898 // Compute hot/cold threshold based on profile. This will be used for cold 899 // context profile merging/trimming. 900 computeSummaryAndThreshold(); 901 902 // Run global pre-inliner to adjust/merge context profile based on estimated 903 // inline decisions. 904 if (EnableCSPreInliner) { 905 CSPreInliner(ProfileMap, *Binary, HotCountThreshold, ColdCountThreshold) 906 .run(); 907 // Turn off the profile merger by default unless it is explicitly enabled. 908 if (!CSProfMergeColdContext.getNumOccurrences()) 909 CSProfMergeColdContext = false; 910 } 911 912 // Trim and merge cold context profile using cold threshold above. 913 if (TrimColdProfile || CSProfMergeColdContext) { 914 SampleContextTrimmer(ProfileMap) 915 .trimAndMergeColdContextProfiles( 916 HotCountThreshold, TrimColdProfile, CSProfMergeColdContext, 917 CSProfMaxColdContextDepth, EnableCSPreInliner); 918 } 919 920 // Merge function samples of CS profile to calculate profile density. 921 sampleprof::SampleProfileMap ContextLessProfiles; 922 for (const auto &I : ProfileMap) { 923 ContextLessProfiles[I.second.getName()].merge(I.second); 924 } 925 926 calculateAndShowDensity(ContextLessProfiles); 927 if (GenCSNestedProfile) { 928 CSProfileConverter CSConverter(ProfileMap); 929 CSConverter.convertProfiles(); 930 FunctionSamples::ProfileIsCSFlat = false; 931 FunctionSamples::ProfileIsCSNested = EnableCSPreInliner; 932 } 933 } 934 935 void ProfileGeneratorBase::computeSummaryAndThreshold() { 936 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 937 auto Summary = Builder.computeSummaryForProfiles(ProfileMap); 938 HotCountThreshold = ProfileSummaryBuilder::getHotCountThreshold( 939 (Summary->getDetailedSummary())); 940 ColdCountThreshold = ProfileSummaryBuilder::getColdCountThreshold( 941 (Summary->getDetailedSummary())); 942 } 943 944 void ProfileGeneratorBase::extractProbesFromRange( 945 const RangeSample &RangeCounter, ProbeCounterMap &ProbeCounter, 946 bool FindDisjointRanges) { 947 const RangeSample *PRanges = &RangeCounter; 948 RangeSample Ranges; 949 if (FindDisjointRanges) { 950 findDisjointRanges(Ranges, RangeCounter); 951 PRanges = &Ranges; 952 } 953 954 for (const auto &Range : *PRanges) { 955 uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first); 956 uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second); 957 uint64_t Count = Range.second; 958 959 InstructionPointer IP(Binary, RangeBegin, true); 960 // Disjoint ranges may have range in the middle of two instr, 961 // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range 962 // can be Addr1+1 to Addr2-1. We should ignore such range. 963 if (IP.Address > RangeEnd) 964 continue; 965 966 do { 967 const AddressProbesMap &Address2ProbesMap = 968 Binary->getAddress2ProbesMap(); 969 auto It = Address2ProbesMap.find(IP.Address); 970 if (It != Address2ProbesMap.end()) { 971 for (const auto &Probe : It->second) { 972 ProbeCounter[&Probe] += Count; 973 } 974 } 975 } while (IP.advance() && IP.Address <= RangeEnd); 976 } 977 } 978 979 static void 980 extractPrefixContextStack(SampleContextFrameVector &ContextStack, 981 const SmallVectorImpl<uint64_t> &Addresses, 982 ProfiledBinary *Binary) { 983 SmallVector<const MCDecodedPseudoProbe *, 16> Probes; 984 for (auto Addr : reverse(Addresses)) { 985 const MCDecodedPseudoProbe *CallProbe = Binary->getCallProbeForAddr(Addr); 986 // These could be the cases when a probe is not found at a calliste. Cutting 987 // off the context from here since the inliner will not know how to consume 988 // a context with unknown callsites. 989 // 1. for functions that are not sampled when 990 // --decode-probe-for-profiled-functions-only is on. 991 // 2. for a merged callsite. Callsite merging may cause the loss of original 992 // probe IDs. 993 // 3. for an external callsite. 994 if (!CallProbe) 995 break; 996 Probes.push_back(CallProbe); 997 } 998 999 std::reverse(Probes.begin(), Probes.end()); 1000 1001 // Extract context stack for reusing, leaf context stack will be added 1002 // compressed while looking up function profile. 1003 for (const auto *P : Probes) { 1004 Binary->getInlineContextForProbe(P, ContextStack, true); 1005 } 1006 } 1007 1008 void CSProfileGenerator::generateProbeBasedProfile() { 1009 // Enable pseudo probe functionalities in SampleProf 1010 FunctionSamples::ProfileIsProbeBased = true; 1011 for (const auto &CI : *SampleCounters) { 1012 const AddrBasedCtxKey *CtxKey = 1013 dyn_cast<AddrBasedCtxKey>(CI.first.getPtr()); 1014 SampleContextFrameVector ContextStack; 1015 extractPrefixContextStack(ContextStack, CtxKey->Context, Binary); 1016 // Fill in function body samples from probes, also infer caller's samples 1017 // from callee's probe 1018 populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStack); 1019 // Fill in boundary samples for a call probe 1020 populateBoundarySamplesWithProbes(CI.second.BranchCounter, ContextStack); 1021 } 1022 } 1023 1024 void CSProfileGenerator::populateBodySamplesWithProbes( 1025 const RangeSample &RangeCounter, SampleContextFrames ContextStack) { 1026 ProbeCounterMap ProbeCounter; 1027 // Extract the top frame probes by looking up each address among the range in 1028 // the Address2ProbeMap 1029 extractProbesFromRange(RangeCounter, ProbeCounter); 1030 std::unordered_map<MCDecodedPseudoProbeInlineTree *, 1031 std::unordered_set<FunctionSamples *>> 1032 FrameSamples; 1033 for (const auto &PI : ProbeCounter) { 1034 const MCDecodedPseudoProbe *Probe = PI.first; 1035 uint64_t Count = PI.second; 1036 // Disjoint ranges have introduce zero-filled gap that 1037 // doesn't belong to current context, filter them out. 1038 if (!Probe->isBlock() || Count == 0) 1039 continue; 1040 FunctionSamples &FunctionProfile = 1041 getFunctionProfileForLeafProbe(ContextStack, Probe); 1042 // Record the current frame and FunctionProfile whenever samples are 1043 // collected for non-danglie probes. This is for reporting all of the 1044 // zero count probes of the frame later. 1045 FrameSamples[Probe->getInlineTreeNode()].insert(&FunctionProfile); 1046 FunctionProfile.addBodySamplesForProbe(Probe->getIndex(), Count); 1047 FunctionProfile.addTotalSamples(Count); 1048 if (Probe->isEntry()) { 1049 FunctionProfile.addHeadSamples(Count); 1050 // Look up for the caller's function profile 1051 const auto *InlinerDesc = Binary->getInlinerDescForProbe(Probe); 1052 SampleContextFrames CalleeContextId = 1053 FunctionProfile.getContext().getContextFrames(); 1054 if (InlinerDesc != nullptr && CalleeContextId.size() > 1) { 1055 // Since the context id will be compressed, we have to use callee's 1056 // context id to infer caller's context id to ensure they share the 1057 // same context prefix. 1058 SampleContextFrameVector CallerContextId; 1059 SampleContextFrame &&CallerLeafFrameLoc = 1060 getCallerContext(CalleeContextId, CallerContextId); 1061 uint64_t CallerIndex = CallerLeafFrameLoc.Location.LineOffset; 1062 assert(CallerIndex && 1063 "Inferred caller's location index shouldn't be zero!"); 1064 FunctionSamples &CallerProfile = 1065 getFunctionProfileForContext(CallerContextId); 1066 CallerProfile.setFunctionHash(InlinerDesc->FuncHash); 1067 CallerProfile.addBodySamples(CallerIndex, 0, Count); 1068 CallerProfile.addTotalSamples(Count); 1069 CallerProfile.addCalledTargetSamples( 1070 CallerIndex, 0, FunctionProfile.getContext().getName(), Count); 1071 } 1072 } 1073 } 1074 1075 // Assign zero count for remaining probes without sample hits to 1076 // differentiate from probes optimized away, of which the counts are unknown 1077 // and will be inferred by the compiler. 1078 for (auto &I : FrameSamples) { 1079 for (auto *FunctionProfile : I.second) { 1080 for (auto *Probe : I.first->getProbes()) { 1081 FunctionProfile->addBodySamplesForProbe(Probe->getIndex(), 0); 1082 } 1083 } 1084 } 1085 } 1086 1087 void CSProfileGenerator::populateBoundarySamplesWithProbes( 1088 const BranchSample &BranchCounter, SampleContextFrames ContextStack) { 1089 for (const auto &BI : BranchCounter) { 1090 uint64_t SourceOffset = BI.first.first; 1091 uint64_t TargetOffset = BI.first.second; 1092 uint64_t Count = BI.second; 1093 uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset); 1094 const MCDecodedPseudoProbe *CallProbe = 1095 Binary->getCallProbeForAddr(SourceAddress); 1096 if (CallProbe == nullptr) 1097 continue; 1098 FunctionSamples &FunctionProfile = 1099 getFunctionProfileForLeafProbe(ContextStack, CallProbe); 1100 FunctionProfile.addBodySamples(CallProbe->getIndex(), 0, Count); 1101 FunctionProfile.addTotalSamples(Count); 1102 StringRef CalleeName = getCalleeNameForOffset(TargetOffset); 1103 if (CalleeName.size() == 0) 1104 continue; 1105 FunctionProfile.addCalledTargetSamples(CallProbe->getIndex(), 0, CalleeName, 1106 Count); 1107 } 1108 } 1109 1110 FunctionSamples &CSProfileGenerator::getFunctionProfileForLeafProbe( 1111 SampleContextFrames ContextStack, const MCDecodedPseudoProbe *LeafProbe) { 1112 1113 // Explicitly copy the context for appending the leaf context 1114 SampleContextFrameVector NewContextStack(ContextStack.begin(), 1115 ContextStack.end()); 1116 Binary->getInlineContextForProbe(LeafProbe, NewContextStack, true); 1117 // For leaf inlined context with the top frame, we should strip off the top 1118 // frame's probe id, like: 1119 // Inlined stack: [foo:1, bar:2], the ContextId will be "foo:1 @ bar" 1120 auto LeafFrame = NewContextStack.back(); 1121 LeafFrame.Location = LineLocation(0, 0); 1122 NewContextStack.pop_back(); 1123 // Compress the context string except for the leaf frame 1124 CSProfileGenerator::compressRecursionContext(NewContextStack); 1125 CSProfileGenerator::trimContext(NewContextStack); 1126 NewContextStack.push_back(LeafFrame); 1127 1128 const auto *FuncDesc = Binary->getFuncDescForGUID(LeafProbe->getGuid()); 1129 bool WasLeafInlined = LeafProbe->getInlineTreeNode()->hasInlineSite(); 1130 FunctionSamples &FunctionProile = 1131 getFunctionProfileForContext(NewContextStack, WasLeafInlined); 1132 FunctionProile.setFunctionHash(FuncDesc->FuncHash); 1133 return FunctionProile; 1134 } 1135 1136 } // end namespace sampleprof 1137 } // end namespace llvm 1138