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