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 (const 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 (const auto &Item : Boundaries) {
310     uint64_t Address = Item.first;
311     const 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     exitWithError("Probe based profile generation not supported for AutoFDO, "
387       "consider dropping `--ignore-stack-samples` or adding `--use-dwarf-correlation`.");
388   } else {
389     generateLineNumBasedProfile();
390   }
391   postProcessProfiles();
392 }
393 
394 void ProfileGenerator::postProcessProfiles() {
395   computeSummaryAndThreshold();
396   trimColdProfiles(ProfileMap, ColdCountThreshold);
397   calculateAndShowDensity(ProfileMap);
398 }
399 
400 void ProfileGenerator::trimColdProfiles(const SampleProfileMap &Profiles,
401                                         uint64_t ColdCntThreshold) {
402   if (!TrimColdProfile)
403     return;
404 
405   // Move cold profiles into a tmp container.
406   std::vector<SampleContext> ColdProfiles;
407   for (const auto &I : ProfileMap) {
408     if (I.second.getTotalSamples() < ColdCntThreshold)
409       ColdProfiles.emplace_back(I.first);
410   }
411 
412   // Remove the cold profile from ProfileMap.
413   for (const auto &I : ColdProfiles)
414     ProfileMap.erase(I);
415 }
416 
417 void ProfileGenerator::generateLineNumBasedProfile() {
418   assert(SampleCounters.size() == 1 &&
419          "Must have one entry for profile generation.");
420   const SampleCounter &SC = SampleCounters.begin()->second;
421   // Fill in function body samples
422   populateBodySamplesForAllFunctions(SC.RangeCounter);
423   // Fill in boundary sample counts as well as call site samples for calls
424   populateBoundarySamplesForAllFunctions(SC.BranchCounter);
425 
426   updateTotalSamples();
427 }
428 
429 FunctionSamples &ProfileGenerator::getLeafProfileAndAddTotalSamples(
430     const SampleContextFrameVector &FrameVec, uint64_t Count) {
431   // Get top level profile
432   FunctionSamples *FunctionProfile =
433       &getTopLevelFunctionProfile(FrameVec[0].FuncName);
434   FunctionProfile->addTotalSamples(Count);
435 
436   for (size_t I = 1; I < FrameVec.size(); I++) {
437     LineLocation Callsite(
438         FrameVec[I - 1].Location.LineOffset,
439         getBaseDiscriminator(FrameVec[I - 1].Location.Discriminator));
440     FunctionSamplesMap &SamplesMap =
441         FunctionProfile->functionSamplesAt(Callsite);
442     auto Ret =
443         SamplesMap.emplace(FrameVec[I].FuncName.str(), FunctionSamples());
444     if (Ret.second) {
445       SampleContext Context(FrameVec[I].FuncName);
446       Ret.first->second.setContext(Context);
447     }
448     FunctionProfile = &Ret.first->second;
449     FunctionProfile->addTotalSamples(Count);
450   }
451 
452   return *FunctionProfile;
453 }
454 
455 RangeSample
456 ProfileGenerator::preprocessRangeCounter(const RangeSample &RangeCounter) {
457   RangeSample Ranges(RangeCounter.begin(), RangeCounter.end());
458   if (FillZeroForAllFuncs) {
459     for (auto &FuncI : Binary->getAllBinaryFunctions()) {
460       for (auto &R : FuncI.second.Ranges) {
461         Ranges[{R.first, R.second - 1}] += 0;
462       }
463     }
464   } else {
465     // For each range, we search for all ranges of the function it belongs to
466     // and initialize it with zero count, so it remains zero if doesn't hit any
467     // samples. This is to be consistent with compiler that interpret zero count
468     // as unexecuted(cold).
469     for (const auto &I : RangeCounter) {
470       uint64_t StartOffset = I.first.first;
471       for (const auto &Range : Binary->getRangesForOffset(StartOffset))
472         Ranges[{Range.first, Range.second - 1}] += 0;
473     }
474   }
475   RangeSample DisjointRanges;
476   findDisjointRanges(DisjointRanges, Ranges);
477   return DisjointRanges;
478 }
479 
480 void ProfileGenerator::populateBodySamplesForAllFunctions(
481     const RangeSample &RangeCounter) {
482   for (const auto &Range : preprocessRangeCounter(RangeCounter)) {
483     uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
484     uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
485     uint64_t Count = Range.second;
486 
487     InstructionPointer IP(Binary, RangeBegin, true);
488     // Disjoint ranges may have range in the middle of two instr,
489     // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
490     // can be Addr1+1 to Addr2-1. We should ignore such range.
491     if (IP.Address > RangeEnd)
492       continue;
493 
494     do {
495       uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
496       const SampleContextFrameVector &FrameVec =
497           Binary->getFrameLocationStack(Offset);
498       if (!FrameVec.empty()) {
499         // FIXME: As accumulating total count per instruction caused some
500         // regression, we changed to accumulate total count per byte as a
501         // workaround. Tuning hotness threshold on the compiler side might be
502         // necessary in the future.
503         FunctionSamples &FunctionProfile = getLeafProfileAndAddTotalSamples(
504             FrameVec, Count * Binary->getInstSize(Offset));
505         updateBodySamplesforFunctionProfile(FunctionProfile, FrameVec.back(),
506                                             Count);
507       }
508     } while (IP.advance() && IP.Address <= RangeEnd);
509   }
510 }
511 
512 StringRef ProfileGeneratorBase::getCalleeNameForOffset(uint64_t TargetOffset) {
513   // Get the function range by branch target if it's a call branch.
514   auto *FRange = Binary->findFuncRangeForStartOffset(TargetOffset);
515 
516   // We won't accumulate sample count for a range whose start is not the real
517   // function entry such as outlined function or inner labels.
518   if (!FRange || !FRange->IsFuncEntry)
519     return StringRef();
520 
521   return FunctionSamples::getCanonicalFnName(FRange->getFuncName());
522 }
523 
524 void ProfileGenerator::populateBoundarySamplesForAllFunctions(
525     const BranchSample &BranchCounters) {
526   for (const auto &Entry : BranchCounters) {
527     uint64_t SourceOffset = Entry.first.first;
528     uint64_t TargetOffset = Entry.first.second;
529     uint64_t Count = Entry.second;
530     assert(Count != 0 && "Unexpected zero weight branch");
531 
532     StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
533     if (CalleeName.size() == 0)
534       continue;
535     // Record called target sample and its count.
536     const SampleContextFrameVector &FrameVec =
537         Binary->getFrameLocationStack(SourceOffset);
538     if (!FrameVec.empty()) {
539       FunctionSamples &FunctionProfile =
540           getLeafProfileAndAddTotalSamples(FrameVec, 0);
541       FunctionProfile.addCalledTargetSamples(
542           FrameVec.back().Location.LineOffset,
543           getBaseDiscriminator(FrameVec.back().Location.Discriminator),
544           CalleeName, Count);
545     }
546     // Add head samples for callee.
547     FunctionSamples &CalleeProfile = getTopLevelFunctionProfile(CalleeName);
548     CalleeProfile.addHeadSamples(Count);
549   }
550 }
551 
552 void ProfileGeneratorBase::calculateAndShowDensity(
553     const SampleProfileMap &Profiles) {
554   double Density = calculateDensity(Profiles, HotCountThreshold);
555   showDensitySuggestion(Density);
556 }
557 
558 FunctionSamples &CSProfileGenerator::getFunctionProfileForContext(
559     const SampleContextFrameVector &Context, bool WasLeafInlined) {
560   auto I = ProfileMap.find(SampleContext(Context));
561   if (I == ProfileMap.end()) {
562     // Save the new context for future references.
563     SampleContextFrames NewContext = *Contexts.insert(Context).first;
564     SampleContext FContext(NewContext, RawContext);
565     auto Ret = ProfileMap.emplace(FContext, FunctionSamples());
566     if (WasLeafInlined)
567       FContext.setAttribute(ContextWasInlined);
568     FunctionSamples &FProfile = Ret.first->second;
569     FProfile.setContext(FContext);
570     return Ret.first->second;
571   }
572   return I->second;
573 }
574 
575 void CSProfileGenerator::generateProfile() {
576   FunctionSamples::ProfileIsCSFlat = true;
577 
578   if (Binary->getTrackFuncContextSize())
579     computeSizeForProfiledFunctions();
580 
581   if (Binary->usePseudoProbes()) {
582     // Enable pseudo probe functionalities in SampleProf
583     FunctionSamples::ProfileIsProbeBased = true;
584     generateProbeBasedProfile();
585   } else {
586     generateLineNumBasedProfile();
587   }
588   postProcessProfiles();
589 }
590 
591 void CSProfileGenerator::computeSizeForProfiledFunctions() {
592   std::unordered_set<const BinaryFunction *> ProfiledFunctions;
593 
594   // Go through all the ranges in the CS counters, use the start of the range to
595   // look up the function it belongs and record the function.
596   for (const auto &CI : SampleCounters) {
597     for (const auto &Item : CI.second.RangeCounter) {
598       // FIXME: Filter the bogus crossing function range.
599       uint64_t StartOffset = Item.first.first;
600       if (FuncRange *FRange = Binary->findFuncRangeForOffset(StartOffset))
601         ProfiledFunctions.insert(FRange->Func);
602     }
603   }
604 
605   for (auto *Func : ProfiledFunctions)
606     Binary->computeInlinedContextSizeForFunc(Func);
607 
608   // Flush the symbolizer to save memory.
609   Binary->flushSymbolizer();
610 }
611 
612 void CSProfileGenerator::generateLineNumBasedProfile() {
613   for (const auto &CI : SampleCounters) {
614     const auto *CtxKey = cast<StringBasedCtxKey>(CI.first.getPtr());
615 
616     // Get or create function profile for the range
617     FunctionSamples &FunctionProfile =
618         getFunctionProfileForContext(CtxKey->Context, CtxKey->WasLeafInlined);
619 
620     // Fill in function body samples
621     populateBodySamplesForFunction(FunctionProfile, CI.second.RangeCounter);
622     // Fill in boundary sample counts as well as call site samples for calls
623     populateBoundarySamplesForFunction(CtxKey->Context, FunctionProfile,
624                                        CI.second.BranchCounter);
625   }
626   // Fill in call site value sample for inlined calls and also use context to
627   // infer missing samples. Since we don't have call count for inlined
628   // functions, we estimate it from inlinee's profile using the entry of the
629   // body sample.
630   populateInferredFunctionSamples();
631 
632   updateTotalSamples();
633 }
634 
635 void CSProfileGenerator::populateBodySamplesForFunction(
636     FunctionSamples &FunctionProfile, const RangeSample &RangeCounter) {
637   // Compute disjoint ranges first, so we can use MAX
638   // for calculating count for each location.
639   RangeSample Ranges;
640   findDisjointRanges(Ranges, RangeCounter);
641   for (const auto &Range : Ranges) {
642     uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
643     uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
644     uint64_t Count = Range.second;
645     // Disjoint ranges have introduce zero-filled gap that
646     // doesn't belong to current context, filter them out.
647     if (Count == 0)
648       continue;
649 
650     InstructionPointer IP(Binary, RangeBegin, true);
651     // Disjoint ranges may have range in the middle of two instr,
652     // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
653     // can be Addr1+1 to Addr2-1. We should ignore such range.
654     if (IP.Address > RangeEnd)
655       continue;
656 
657     do {
658       uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
659       auto LeafLoc = Binary->getInlineLeafFrameLoc(Offset);
660       if (LeafLoc.hasValue()) {
661         // Recording body sample for this specific context
662         updateBodySamplesforFunctionProfile(FunctionProfile, *LeafLoc, Count);
663         FunctionProfile.addTotalSamples(Count);
664       }
665     } while (IP.advance() && IP.Address <= RangeEnd);
666   }
667 }
668 
669 void CSProfileGenerator::populateBoundarySamplesForFunction(
670     SampleContextFrames ContextId, FunctionSamples &FunctionProfile,
671     const BranchSample &BranchCounters) {
672 
673   for (const auto &Entry : BranchCounters) {
674     uint64_t SourceOffset = Entry.first.first;
675     uint64_t TargetOffset = Entry.first.second;
676     uint64_t Count = Entry.second;
677     assert(Count != 0 && "Unexpected zero weight branch");
678 
679     StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
680     if (CalleeName.size() == 0)
681       continue;
682 
683     // Record called target sample and its count
684     auto LeafLoc = Binary->getInlineLeafFrameLoc(SourceOffset);
685     if (!LeafLoc.hasValue())
686       continue;
687     FunctionProfile.addCalledTargetSamples(
688         LeafLoc->Location.LineOffset,
689         getBaseDiscriminator(LeafLoc->Location.Discriminator), CalleeName,
690         Count);
691 
692     // Record head sample for called target(callee)
693     SampleContextFrameVector CalleeCtx(ContextId.begin(), ContextId.end());
694     assert(CalleeCtx.back().FuncName == LeafLoc->FuncName &&
695            "Leaf function name doesn't match");
696     CalleeCtx.back() = *LeafLoc;
697     CalleeCtx.emplace_back(CalleeName, LineLocation(0, 0));
698     FunctionSamples &CalleeProfile = getFunctionProfileForContext(CalleeCtx);
699     CalleeProfile.addHeadSamples(Count);
700   }
701 }
702 
703 static SampleContextFrame
704 getCallerContext(SampleContextFrames CalleeContext,
705                  SampleContextFrameVector &CallerContext) {
706   assert(CalleeContext.size() > 1 && "Unexpected empty context");
707   CalleeContext = CalleeContext.drop_back();
708   CallerContext.assign(CalleeContext.begin(), CalleeContext.end());
709   SampleContextFrame CallerFrame = CallerContext.back();
710   CallerContext.back().Location = LineLocation(0, 0);
711   return CallerFrame;
712 }
713 
714 void CSProfileGenerator::populateInferredFunctionSamples() {
715   for (const auto &Item : ProfileMap) {
716     const auto &CalleeContext = Item.first;
717     const FunctionSamples &CalleeProfile = Item.second;
718 
719     // If we already have head sample counts, we must have value profile
720     // for call sites added already. Skip to avoid double counting.
721     if (CalleeProfile.getHeadSamples())
722       continue;
723     // If we don't have context, nothing to do for caller's call site.
724     // This could happen for entry point function.
725     if (CalleeContext.isBaseContext())
726       continue;
727 
728     // Infer Caller's frame loc and context ID through string splitting
729     SampleContextFrameVector CallerContextId;
730     SampleContextFrame &&CallerLeafFrameLoc =
731         getCallerContext(CalleeContext.getContextFrames(), CallerContextId);
732     SampleContextFrames CallerContext(CallerContextId);
733 
734     // It's possible that we haven't seen any sample directly in the caller,
735     // in which case CallerProfile will not exist. But we can't modify
736     // ProfileMap while iterating it.
737     // TODO: created function profile for those callers too
738     if (ProfileMap.find(CallerContext) == ProfileMap.end())
739       continue;
740     FunctionSamples &CallerProfile = ProfileMap[CallerContext];
741 
742     // Since we don't have call count for inlined functions, we
743     // estimate it from inlinee's profile using entry body sample.
744     uint64_t EstimatedCallCount = CalleeProfile.getEntrySamples();
745     // If we don't have samples with location, use 1 to indicate live.
746     if (!EstimatedCallCount && !CalleeProfile.getBodySamples().size())
747       EstimatedCallCount = 1;
748     CallerProfile.addCalledTargetSamples(
749         CallerLeafFrameLoc.Location.LineOffset,
750         CallerLeafFrameLoc.Location.Discriminator,
751         CalleeProfile.getContext().getName(), EstimatedCallCount);
752     CallerProfile.addBodySamples(CallerLeafFrameLoc.Location.LineOffset,
753                                  CallerLeafFrameLoc.Location.Discriminator,
754                                  EstimatedCallCount);
755     CallerProfile.addTotalSamples(EstimatedCallCount);
756   }
757 }
758 
759 void CSProfileGenerator::postProcessProfiles() {
760   // Compute hot/cold threshold based on profile. This will be used for cold
761   // context profile merging/trimming.
762   computeSummaryAndThreshold();
763 
764   // Run global pre-inliner to adjust/merge context profile based on estimated
765   // inline decisions.
766   if (EnableCSPreInliner) {
767     CSPreInliner(ProfileMap, *Binary, HotCountThreshold, ColdCountThreshold)
768         .run();
769     // Turn off the profile merger by default unless it is explicitly enabled.
770     if (!CSProfMergeColdContext.getNumOccurrences())
771       CSProfMergeColdContext = false;
772   }
773 
774   // Trim and merge cold context profile using cold threshold above.
775   if (TrimColdProfile || CSProfMergeColdContext) {
776     SampleContextTrimmer(ProfileMap)
777         .trimAndMergeColdContextProfiles(
778             HotCountThreshold, TrimColdProfile, CSProfMergeColdContext,
779             CSProfMaxColdContextDepth, EnableCSPreInliner);
780   }
781 
782   // Merge function samples of CS profile to calculate profile density.
783   sampleprof::SampleProfileMap ContextLessProfiles;
784   for (const auto &I : ProfileMap) {
785     ContextLessProfiles[I.second.getName()].merge(I.second);
786   }
787 
788   calculateAndShowDensity(ContextLessProfiles);
789   if (GenCSNestedProfile) {
790     CSProfileConverter CSConverter(ProfileMap);
791     CSConverter.convertProfiles();
792     FunctionSamples::ProfileIsCSFlat = false;
793     FunctionSamples::ProfileIsCSNested = EnableCSPreInliner;
794   }
795 }
796 
797 void ProfileGeneratorBase::computeSummaryAndThreshold() {
798   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
799   auto Summary = Builder.computeSummaryForProfiles(ProfileMap);
800   HotCountThreshold = ProfileSummaryBuilder::getHotCountThreshold(
801       (Summary->getDetailedSummary()));
802   ColdCountThreshold = ProfileSummaryBuilder::getColdCountThreshold(
803       (Summary->getDetailedSummary()));
804 }
805 
806 // Helper function to extract context prefix string stack
807 // Extract context stack for reusing, leaf context stack will
808 // be added compressed while looking up function profile
809 static void extractPrefixContextStack(
810     SampleContextFrameVector &ContextStack,
811     const SmallVectorImpl<const MCDecodedPseudoProbe *> &Probes,
812     ProfiledBinary *Binary) {
813   for (const auto *P : Probes) {
814     Binary->getInlineContextForProbe(P, ContextStack, true);
815   }
816 }
817 
818 void CSProfileGenerator::generateProbeBasedProfile() {
819   for (const auto &CI : SampleCounters) {
820     const auto *CtxKey = cast<ProbeBasedCtxKey>(CI.first.getPtr());
821     SampleContextFrameVector ContextStack;
822     extractPrefixContextStack(ContextStack, CtxKey->Probes, Binary);
823     // Fill in function body samples from probes, also infer caller's samples
824     // from callee's probe
825     populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStack);
826     // Fill in boundary samples for a call probe
827     populateBoundarySamplesWithProbes(CI.second.BranchCounter, ContextStack);
828   }
829 }
830 
831 void CSProfileGenerator::extractProbesFromRange(const RangeSample &RangeCounter,
832                                                 ProbeCounterMap &ProbeCounter) {
833   RangeSample Ranges;
834   findDisjointRanges(Ranges, RangeCounter);
835   for (const auto &Range : Ranges) {
836     uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
837     uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
838     uint64_t Count = Range.second;
839     // Disjoint ranges have introduce zero-filled gap that
840     // doesn't belong to current context, filter them out.
841     if (Count == 0)
842       continue;
843 
844     InstructionPointer IP(Binary, RangeBegin, true);
845     // Disjoint ranges may have range in the middle of two instr,
846     // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
847     // can be Addr1+1 to Addr2-1. We should ignore such range.
848     if (IP.Address > RangeEnd)
849       continue;
850 
851     do {
852       const AddressProbesMap &Address2ProbesMap =
853           Binary->getAddress2ProbesMap();
854       auto It = Address2ProbesMap.find(IP.Address);
855       if (It != Address2ProbesMap.end()) {
856         for (const auto &Probe : It->second) {
857           if (!Probe.isBlock())
858             continue;
859           ProbeCounter[&Probe] += Count;
860         }
861       }
862     } while (IP.advance() && IP.Address <= RangeEnd);
863   }
864 }
865 
866 void CSProfileGenerator::populateBodySamplesWithProbes(
867     const RangeSample &RangeCounter, SampleContextFrames ContextStack) {
868   ProbeCounterMap ProbeCounter;
869   // Extract the top frame probes by looking up each address among the range in
870   // the Address2ProbeMap
871   extractProbesFromRange(RangeCounter, ProbeCounter);
872   std::unordered_map<MCDecodedPseudoProbeInlineTree *,
873                      std::unordered_set<FunctionSamples *>>
874       FrameSamples;
875   for (const auto &PI : ProbeCounter) {
876     const MCDecodedPseudoProbe *Probe = PI.first;
877     uint64_t Count = PI.second;
878     FunctionSamples &FunctionProfile =
879         getFunctionProfileForLeafProbe(ContextStack, Probe);
880     // Record the current frame and FunctionProfile whenever samples are
881     // collected for non-danglie probes. This is for reporting all of the
882     // zero count probes of the frame later.
883     FrameSamples[Probe->getInlineTreeNode()].insert(&FunctionProfile);
884     FunctionProfile.addBodySamplesForProbe(Probe->getIndex(), Count);
885     FunctionProfile.addTotalSamples(Count);
886     if (Probe->isEntry()) {
887       FunctionProfile.addHeadSamples(Count);
888       // Look up for the caller's function profile
889       const auto *InlinerDesc = Binary->getInlinerDescForProbe(Probe);
890       SampleContextFrames CalleeContextId =
891           FunctionProfile.getContext().getContextFrames();
892       if (InlinerDesc != nullptr && CalleeContextId.size() > 1) {
893         // Since the context id will be compressed, we have to use callee's
894         // context id to infer caller's context id to ensure they share the
895         // same context prefix.
896         SampleContextFrameVector CallerContextId;
897         SampleContextFrame &&CallerLeafFrameLoc =
898             getCallerContext(CalleeContextId, CallerContextId);
899         uint64_t CallerIndex = CallerLeafFrameLoc.Location.LineOffset;
900         assert(CallerIndex &&
901                "Inferred caller's location index shouldn't be zero!");
902         FunctionSamples &CallerProfile =
903             getFunctionProfileForContext(CallerContextId);
904         CallerProfile.setFunctionHash(InlinerDesc->FuncHash);
905         CallerProfile.addBodySamples(CallerIndex, 0, Count);
906         CallerProfile.addTotalSamples(Count);
907         CallerProfile.addCalledTargetSamples(
908             CallerIndex, 0, FunctionProfile.getContext().getName(), Count);
909       }
910     }
911   }
912 
913   // Assign zero count for remaining probes without sample hits to
914   // differentiate from probes optimized away, of which the counts are unknown
915   // and will be inferred by the compiler.
916   for (auto &I : FrameSamples) {
917     for (auto *FunctionProfile : I.second) {
918       for (auto *Probe : I.first->getProbes()) {
919         FunctionProfile->addBodySamplesForProbe(Probe->getIndex(), 0);
920       }
921     }
922   }
923 }
924 
925 void CSProfileGenerator::populateBoundarySamplesWithProbes(
926     const BranchSample &BranchCounter, SampleContextFrames ContextStack) {
927   for (const auto &BI : BranchCounter) {
928     uint64_t SourceOffset = BI.first.first;
929     uint64_t TargetOffset = BI.first.second;
930     uint64_t Count = BI.second;
931     uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset);
932     const MCDecodedPseudoProbe *CallProbe =
933         Binary->getCallProbeForAddr(SourceAddress);
934     if (CallProbe == nullptr)
935       continue;
936     FunctionSamples &FunctionProfile =
937         getFunctionProfileForLeafProbe(ContextStack, CallProbe);
938     FunctionProfile.addBodySamples(CallProbe->getIndex(), 0, Count);
939     FunctionProfile.addTotalSamples(Count);
940     StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
941     if (CalleeName.size() == 0)
942       continue;
943     FunctionProfile.addCalledTargetSamples(CallProbe->getIndex(), 0, CalleeName,
944                                            Count);
945   }
946 }
947 
948 FunctionSamples &CSProfileGenerator::getFunctionProfileForLeafProbe(
949     SampleContextFrames ContextStack, const MCDecodedPseudoProbe *LeafProbe) {
950 
951   // Explicitly copy the context for appending the leaf context
952   SampleContextFrameVector NewContextStack(ContextStack.begin(),
953                                            ContextStack.end());
954   Binary->getInlineContextForProbe(LeafProbe, NewContextStack, true);
955   // For leaf inlined context with the top frame, we should strip off the top
956   // frame's probe id, like:
957   // Inlined stack: [foo:1, bar:2], the ContextId will be "foo:1 @ bar"
958   auto LeafFrame = NewContextStack.back();
959   LeafFrame.Location = LineLocation(0, 0);
960   NewContextStack.pop_back();
961   // Compress the context string except for the leaf frame
962   CSProfileGenerator::compressRecursionContext(NewContextStack);
963   CSProfileGenerator::trimContext(NewContextStack);
964   NewContextStack.push_back(LeafFrame);
965 
966   const auto *FuncDesc = Binary->getFuncDescForGUID(LeafProbe->getGuid());
967   bool WasLeafInlined = LeafProbe->getInlineTreeNode()->hasInlineSite();
968   FunctionSamples &FunctionProile =
969       getFunctionProfileForContext(NewContextStack, WasLeafInlined);
970   FunctionProile.setFunctionHash(FuncDesc->FuncHash);
971   return FunctionProile;
972 }
973 
974 } // end namespace sampleprof
975 } // end namespace llvm
976