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