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