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 } else { 716 // Update ContextWasInlined attribute for existing contexts. 717 // The current function can be called in two ways: 718 // - when processing a probe of the current frame 719 // - when processing the entry probe of an inlinee's frame, which 720 // is then used to update the callsite count of the current frame. 721 // The two can happen in any order, hence here we are making sure 722 // `ContextWasInlined` is always set as expected. 723 // TODO: Note that the former does not always happen if no probes of the 724 // current frame has samples, and if the latter happens, we could lose the 725 // attribute. This should be fixed. 726 if (WasLeafInlined) 727 I->second.getContext().setAttribute(ContextWasInlined); 728 } 729 730 return I->second; 731 } 732 733 void CSProfileGenerator::generateProfile() { 734 FunctionSamples::ProfileIsCSFlat = true; 735 736 collectProfiledFunctions(); 737 738 if (Binary->usePseudoProbes()) 739 Binary->decodePseudoProbe(); 740 741 if (SampleCounters) { 742 if (Binary->usePseudoProbes()) { 743 generateProbeBasedProfile(); 744 } else { 745 generateLineNumBasedProfile(); 746 } 747 } 748 749 if (Binary->getTrackFuncContextSize()) 750 computeSizeForProfiledFunctions(); 751 752 postProcessProfiles(); 753 } 754 755 void CSProfileGenerator::computeSizeForProfiledFunctions() { 756 std::unordered_set<const BinaryFunction *> ProfiledFunctions; 757 for (auto *Func : Binary->getProfiledFunctions()) 758 Binary->computeInlinedContextSizeForFunc(Func); 759 760 // Flush the symbolizer to save memory. 761 Binary->flushSymbolizer(); 762 } 763 764 void CSProfileGenerator::generateLineNumBasedProfile() { 765 for (const auto &CI : *SampleCounters) { 766 const auto *CtxKey = cast<StringBasedCtxKey>(CI.first.getPtr()); 767 768 // Get or create function profile for the range 769 FunctionSamples &FunctionProfile = 770 getFunctionProfileForContext(CtxKey->Context, CtxKey->WasLeafInlined); 771 772 // Fill in function body samples 773 populateBodySamplesForFunction(FunctionProfile, CI.second.RangeCounter); 774 // Fill in boundary sample counts as well as call site samples for calls 775 populateBoundarySamplesForFunction(CtxKey->Context, FunctionProfile, 776 CI.second.BranchCounter); 777 } 778 // Fill in call site value sample for inlined calls and also use context to 779 // infer missing samples. Since we don't have call count for inlined 780 // functions, we estimate it from inlinee's profile using the entry of the 781 // body sample. 782 populateInferredFunctionSamples(); 783 784 updateTotalSamples(); 785 } 786 787 void CSProfileGenerator::populateBodySamplesForFunction( 788 FunctionSamples &FunctionProfile, const RangeSample &RangeCounter) { 789 // Compute disjoint ranges first, so we can use MAX 790 // for calculating count for each location. 791 RangeSample Ranges; 792 findDisjointRanges(Ranges, RangeCounter); 793 for (const auto &Range : Ranges) { 794 uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first); 795 uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second); 796 uint64_t Count = Range.second; 797 // Disjoint ranges have introduce zero-filled gap that 798 // doesn't belong to current context, filter them out. 799 if (Count == 0) 800 continue; 801 802 InstructionPointer IP(Binary, RangeBegin, true); 803 // Disjoint ranges may have range in the middle of two instr, 804 // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range 805 // can be Addr1+1 to Addr2-1. We should ignore such range. 806 if (IP.Address > RangeEnd) 807 continue; 808 809 do { 810 uint64_t Offset = Binary->virtualAddrToOffset(IP.Address); 811 auto LeafLoc = Binary->getInlineLeafFrameLoc(Offset); 812 if (LeafLoc.hasValue()) { 813 // Recording body sample for this specific context 814 updateBodySamplesforFunctionProfile(FunctionProfile, *LeafLoc, Count); 815 FunctionProfile.addTotalSamples(Count); 816 } 817 } while (IP.advance() && IP.Address <= RangeEnd); 818 } 819 } 820 821 void CSProfileGenerator::populateBoundarySamplesForFunction( 822 SampleContextFrames ContextId, FunctionSamples &FunctionProfile, 823 const BranchSample &BranchCounters) { 824 825 for (const auto &Entry : BranchCounters) { 826 uint64_t SourceOffset = Entry.first.first; 827 uint64_t TargetOffset = Entry.first.second; 828 uint64_t Count = Entry.second; 829 assert(Count != 0 && "Unexpected zero weight branch"); 830 831 StringRef CalleeName = getCalleeNameForOffset(TargetOffset); 832 if (CalleeName.size() == 0) 833 continue; 834 835 // Record called target sample and its count 836 auto LeafLoc = Binary->getInlineLeafFrameLoc(SourceOffset); 837 if (!LeafLoc.hasValue()) 838 continue; 839 FunctionProfile.addCalledTargetSamples( 840 LeafLoc->Location.LineOffset, 841 getBaseDiscriminator(LeafLoc->Location.Discriminator), CalleeName, 842 Count); 843 844 // Record head sample for called target(callee) 845 SampleContextFrameVector CalleeCtx(ContextId.begin(), ContextId.end()); 846 assert(CalleeCtx.back().FuncName == LeafLoc->FuncName && 847 "Leaf function name doesn't match"); 848 CalleeCtx.back() = *LeafLoc; 849 CalleeCtx.emplace_back(CalleeName, LineLocation(0, 0)); 850 FunctionSamples &CalleeProfile = getFunctionProfileForContext(CalleeCtx); 851 CalleeProfile.addHeadSamples(Count); 852 } 853 } 854 855 static SampleContextFrame 856 getCallerContext(SampleContextFrames CalleeContext, 857 SampleContextFrameVector &CallerContext) { 858 assert(CalleeContext.size() > 1 && "Unexpected empty context"); 859 CalleeContext = CalleeContext.drop_back(); 860 CallerContext.assign(CalleeContext.begin(), CalleeContext.end()); 861 SampleContextFrame CallerFrame = CallerContext.back(); 862 CallerContext.back().Location = LineLocation(0, 0); 863 return CallerFrame; 864 } 865 866 void CSProfileGenerator::populateInferredFunctionSamples() { 867 for (const auto &Item : ProfileMap) { 868 const auto &CalleeContext = Item.first; 869 const FunctionSamples &CalleeProfile = Item.second; 870 871 // If we already have head sample counts, we must have value profile 872 // for call sites added already. Skip to avoid double counting. 873 if (CalleeProfile.getHeadSamples()) 874 continue; 875 // If we don't have context, nothing to do for caller's call site. 876 // This could happen for entry point function. 877 if (CalleeContext.isBaseContext()) 878 continue; 879 880 // Infer Caller's frame loc and context ID through string splitting 881 SampleContextFrameVector CallerContextId; 882 SampleContextFrame &&CallerLeafFrameLoc = 883 getCallerContext(CalleeContext.getContextFrames(), CallerContextId); 884 SampleContextFrames CallerContext(CallerContextId); 885 886 // It's possible that we haven't seen any sample directly in the caller, 887 // in which case CallerProfile will not exist. But we can't modify 888 // ProfileMap while iterating it. 889 // TODO: created function profile for those callers too 890 if (ProfileMap.find(CallerContext) == ProfileMap.end()) 891 continue; 892 FunctionSamples &CallerProfile = ProfileMap[CallerContext]; 893 894 // Since we don't have call count for inlined functions, we 895 // estimate it from inlinee's profile using entry body sample. 896 uint64_t EstimatedCallCount = CalleeProfile.getEntrySamples(); 897 // If we don't have samples with location, use 1 to indicate live. 898 if (!EstimatedCallCount && !CalleeProfile.getBodySamples().size()) 899 EstimatedCallCount = 1; 900 CallerProfile.addCalledTargetSamples( 901 CallerLeafFrameLoc.Location.LineOffset, 902 CallerLeafFrameLoc.Location.Discriminator, 903 CalleeProfile.getContext().getName(), EstimatedCallCount); 904 CallerProfile.addBodySamples(CallerLeafFrameLoc.Location.LineOffset, 905 CallerLeafFrameLoc.Location.Discriminator, 906 EstimatedCallCount); 907 CallerProfile.addTotalSamples(EstimatedCallCount); 908 } 909 } 910 911 void CSProfileGenerator::postProcessProfiles() { 912 // Compute hot/cold threshold based on profile. This will be used for cold 913 // context profile merging/trimming. 914 computeSummaryAndThreshold(); 915 916 // Run global pre-inliner to adjust/merge context profile based on estimated 917 // inline decisions. 918 if (EnableCSPreInliner) { 919 CSPreInliner(ProfileMap, *Binary, HotCountThreshold, ColdCountThreshold) 920 .run(); 921 // Turn off the profile merger by default unless it is explicitly enabled. 922 if (!CSProfMergeColdContext.getNumOccurrences()) 923 CSProfMergeColdContext = false; 924 } 925 926 // Trim and merge cold context profile using cold threshold above. 927 if (TrimColdProfile || CSProfMergeColdContext) { 928 SampleContextTrimmer(ProfileMap) 929 .trimAndMergeColdContextProfiles( 930 HotCountThreshold, TrimColdProfile, CSProfMergeColdContext, 931 CSProfMaxColdContextDepth, EnableCSPreInliner); 932 } 933 934 // Merge function samples of CS profile to calculate profile density. 935 sampleprof::SampleProfileMap ContextLessProfiles; 936 for (const auto &I : ProfileMap) { 937 ContextLessProfiles[I.second.getName()].merge(I.second); 938 } 939 940 calculateAndShowDensity(ContextLessProfiles); 941 if (GenCSNestedProfile) { 942 CSProfileConverter CSConverter(ProfileMap); 943 CSConverter.convertProfiles(); 944 FunctionSamples::ProfileIsCSFlat = false; 945 FunctionSamples::ProfileIsCSNested = EnableCSPreInliner; 946 } 947 } 948 949 void ProfileGeneratorBase::computeSummaryAndThreshold() { 950 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 951 auto Summary = Builder.computeSummaryForProfiles(ProfileMap); 952 HotCountThreshold = ProfileSummaryBuilder::getHotCountThreshold( 953 (Summary->getDetailedSummary())); 954 ColdCountThreshold = ProfileSummaryBuilder::getColdCountThreshold( 955 (Summary->getDetailedSummary())); 956 } 957 958 void ProfileGeneratorBase::extractProbesFromRange( 959 const RangeSample &RangeCounter, ProbeCounterMap &ProbeCounter, 960 bool FindDisjointRanges) { 961 const RangeSample *PRanges = &RangeCounter; 962 RangeSample Ranges; 963 if (FindDisjointRanges) { 964 findDisjointRanges(Ranges, RangeCounter); 965 PRanges = &Ranges; 966 } 967 968 for (const auto &Range : *PRanges) { 969 uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first); 970 uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second); 971 uint64_t Count = Range.second; 972 973 InstructionPointer IP(Binary, RangeBegin, true); 974 // Disjoint ranges may have range in the middle of two instr, 975 // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range 976 // can be Addr1+1 to Addr2-1. We should ignore such range. 977 if (IP.Address > RangeEnd) 978 continue; 979 980 do { 981 const AddressProbesMap &Address2ProbesMap = 982 Binary->getAddress2ProbesMap(); 983 auto It = Address2ProbesMap.find(IP.Address); 984 if (It != Address2ProbesMap.end()) { 985 for (const auto &Probe : It->second) { 986 ProbeCounter[&Probe] += Count; 987 } 988 } 989 } while (IP.advance() && IP.Address <= RangeEnd); 990 } 991 } 992 993 static void 994 extractPrefixContextStack(SampleContextFrameVector &ContextStack, 995 const SmallVectorImpl<uint64_t> &Addresses, 996 ProfiledBinary *Binary) { 997 SmallVector<const MCDecodedPseudoProbe *, 16> Probes; 998 for (auto Addr : reverse(Addresses)) { 999 const MCDecodedPseudoProbe *CallProbe = Binary->getCallProbeForAddr(Addr); 1000 // These could be the cases when a probe is not found at a calliste. Cutting 1001 // off the context from here since the inliner will not know how to consume 1002 // a context with unknown callsites. 1003 // 1. for functions that are not sampled when 1004 // --decode-probe-for-profiled-functions-only is on. 1005 // 2. for a merged callsite. Callsite merging may cause the loss of original 1006 // probe IDs. 1007 // 3. for an external callsite. 1008 if (!CallProbe) 1009 break; 1010 Probes.push_back(CallProbe); 1011 } 1012 1013 std::reverse(Probes.begin(), Probes.end()); 1014 1015 // Extract context stack for reusing, leaf context stack will be added 1016 // compressed while looking up function profile. 1017 for (const auto *P : Probes) { 1018 Binary->getInlineContextForProbe(P, ContextStack, true); 1019 } 1020 } 1021 1022 void CSProfileGenerator::generateProbeBasedProfile() { 1023 // Enable pseudo probe functionalities in SampleProf 1024 FunctionSamples::ProfileIsProbeBased = true; 1025 for (const auto &CI : *SampleCounters) { 1026 const AddrBasedCtxKey *CtxKey = 1027 dyn_cast<AddrBasedCtxKey>(CI.first.getPtr()); 1028 SampleContextFrameVector ContextStack; 1029 extractPrefixContextStack(ContextStack, CtxKey->Context, Binary); 1030 // Fill in function body samples from probes, also infer caller's samples 1031 // from callee's probe 1032 populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStack); 1033 // Fill in boundary samples for a call probe 1034 populateBoundarySamplesWithProbes(CI.second.BranchCounter, ContextStack); 1035 } 1036 } 1037 1038 void CSProfileGenerator::populateBodySamplesWithProbes( 1039 const RangeSample &RangeCounter, SampleContextFrames ContextStack) { 1040 ProbeCounterMap ProbeCounter; 1041 // Extract the top frame probes by looking up each address among the range in 1042 // the Address2ProbeMap 1043 extractProbesFromRange(RangeCounter, ProbeCounter); 1044 std::unordered_map<MCDecodedPseudoProbeInlineTree *, 1045 std::unordered_set<FunctionSamples *>> 1046 FrameSamples; 1047 for (const auto &PI : ProbeCounter) { 1048 const MCDecodedPseudoProbe *Probe = PI.first; 1049 uint64_t Count = PI.second; 1050 // Disjoint ranges have introduce zero-filled gap that 1051 // doesn't belong to current context, filter them out. 1052 if (!Probe->isBlock() || Count == 0) 1053 continue; 1054 FunctionSamples &FunctionProfile = 1055 getFunctionProfileForLeafProbe(ContextStack, Probe); 1056 // Record the current frame and FunctionProfile whenever samples are 1057 // collected for non-danglie probes. This is for reporting all of the 1058 // zero count probes of the frame later. 1059 FrameSamples[Probe->getInlineTreeNode()].insert(&FunctionProfile); 1060 FunctionProfile.addBodySamplesForProbe(Probe->getIndex(), Count); 1061 FunctionProfile.addTotalSamples(Count); 1062 if (Probe->isEntry()) { 1063 FunctionProfile.addHeadSamples(Count); 1064 // Look up for the caller's function profile 1065 const auto *InlinerDesc = Binary->getInlinerDescForProbe(Probe); 1066 SampleContextFrames CalleeContextId = 1067 FunctionProfile.getContext().getContextFrames(); 1068 if (InlinerDesc != nullptr && CalleeContextId.size() > 1) { 1069 // Since the context id will be compressed, we have to use callee's 1070 // context id to infer caller's context id to ensure they share the 1071 // same context prefix. 1072 SampleContextFrameVector CallerContextId; 1073 SampleContextFrame &&CallerLeafFrameLoc = 1074 getCallerContext(CalleeContextId, CallerContextId); 1075 uint64_t CallerIndex = CallerLeafFrameLoc.Location.LineOffset; 1076 assert(CallerIndex && 1077 "Inferred caller's location index shouldn't be zero!"); 1078 FunctionSamples &CallerProfile = 1079 getFunctionProfileForContext(CallerContextId); 1080 CallerProfile.setFunctionHash(InlinerDesc->FuncHash); 1081 CallerProfile.addBodySamples(CallerIndex, 0, Count); 1082 CallerProfile.addTotalSamples(Count); 1083 CallerProfile.addCalledTargetSamples( 1084 CallerIndex, 0, FunctionProfile.getContext().getName(), Count); 1085 } 1086 } 1087 } 1088 1089 // Assign zero count for remaining probes without sample hits to 1090 // differentiate from probes optimized away, of which the counts are unknown 1091 // and will be inferred by the compiler. 1092 for (auto &I : FrameSamples) { 1093 for (auto *FunctionProfile : I.second) { 1094 for (auto *Probe : I.first->getProbes()) { 1095 FunctionProfile->addBodySamplesForProbe(Probe->getIndex(), 0); 1096 } 1097 } 1098 } 1099 } 1100 1101 void CSProfileGenerator::populateBoundarySamplesWithProbes( 1102 const BranchSample &BranchCounter, SampleContextFrames ContextStack) { 1103 for (const auto &BI : BranchCounter) { 1104 uint64_t SourceOffset = BI.first.first; 1105 uint64_t TargetOffset = BI.first.second; 1106 uint64_t Count = BI.second; 1107 uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset); 1108 const MCDecodedPseudoProbe *CallProbe = 1109 Binary->getCallProbeForAddr(SourceAddress); 1110 if (CallProbe == nullptr) 1111 continue; 1112 FunctionSamples &FunctionProfile = 1113 getFunctionProfileForLeafProbe(ContextStack, CallProbe); 1114 FunctionProfile.addBodySamples(CallProbe->getIndex(), 0, Count); 1115 FunctionProfile.addTotalSamples(Count); 1116 StringRef CalleeName = getCalleeNameForOffset(TargetOffset); 1117 if (CalleeName.size() == 0) 1118 continue; 1119 FunctionProfile.addCalledTargetSamples(CallProbe->getIndex(), 0, CalleeName, 1120 Count); 1121 } 1122 } 1123 1124 FunctionSamples &CSProfileGenerator::getFunctionProfileForLeafProbe( 1125 SampleContextFrames ContextStack, const MCDecodedPseudoProbe *LeafProbe) { 1126 1127 // Explicitly copy the context for appending the leaf context 1128 SampleContextFrameVector NewContextStack(ContextStack.begin(), 1129 ContextStack.end()); 1130 Binary->getInlineContextForProbe(LeafProbe, NewContextStack, true); 1131 // For leaf inlined context with the top frame, we should strip off the top 1132 // frame's probe id, like: 1133 // Inlined stack: [foo:1, bar:2], the ContextId will be "foo:1 @ bar" 1134 auto LeafFrame = NewContextStack.back(); 1135 LeafFrame.Location = LineLocation(0, 0); 1136 NewContextStack.pop_back(); 1137 // Compress the context string except for the leaf frame 1138 CSProfileGenerator::compressRecursionContext(NewContextStack); 1139 CSProfileGenerator::trimContext(NewContextStack); 1140 NewContextStack.push_back(LeafFrame); 1141 1142 const auto *FuncDesc = Binary->getFuncDescForGUID(LeafProbe->getGuid()); 1143 bool WasLeafInlined = LeafProbe->getInlineTreeNode()->hasInlineSite(); 1144 FunctionSamples &FunctionProile = 1145 getFunctionProfileForContext(NewContextStack, WasLeafInlined); 1146 FunctionProile.setFunctionHash(FuncDesc->FuncHash); 1147 return FunctionProile; 1148 } 1149 1150 } // end namespace sampleprof 1151 } // end namespace llvm 1152