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.contains(".resume") || CalleeName.contains(".cold");
407 }
408 
409 StringRef ProfileGeneratorBase::getCalleeNameForOffset(uint64_t TargetOffset) {
410   // Get the callee name by branch target if it's a call branch.
411   StringRef CalleeName = FunctionSamples::getCanonicalFnName(
412       Binary->getFuncFromStartOffset(TargetOffset));
413 
414   // We won't accumulate sample count againt outlined function.
415   if (CalleeName.size() == 0 || isOutlinedFunction(CalleeName))
416     return StringRef();
417 
418   return CalleeName;
419 }
420 
421 void ProfileGenerator::populateBoundarySamplesForAllFunctions(
422     const BranchSample &BranchCounters) {
423   for (auto Entry : BranchCounters) {
424     uint64_t SourceOffset = Entry.first.first;
425     uint64_t TargetOffset = Entry.first.second;
426     uint64_t Count = Entry.second;
427     assert(Count != 0 && "Unexpected zero weight branch");
428 
429     StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
430     if (CalleeName.size() == 0)
431       continue;
432     // Record called target sample and its count.
433     const SampleContextFrameVector &FrameVec =
434         Binary->getFrameLocationStack(SourceOffset);
435     if (!FrameVec.empty()) {
436       FunctionSamples &FunctionProfile =
437           getLeafProfileAndAddTotalSamples(FrameVec, Count);
438       FunctionProfile.addCalledTargetSamples(
439           FrameVec.back().Location.LineOffset,
440           getBaseDiscriminator(FrameVec.back().Location.Discriminator),
441           CalleeName, Count);
442     }
443     // Add head samples for callee.
444     FunctionSamples &CalleeProfile = getTopLevelFunctionProfile(CalleeName);
445     CalleeProfile.addHeadSamples(Count);
446   }
447 }
448 
449 FunctionSamples &CSProfileGenerator::getFunctionProfileForContext(
450     const SampleContextFrameVector &Context, bool WasLeafInlined) {
451   auto I = ProfileMap.find(SampleContext(Context));
452   if (I == ProfileMap.end()) {
453     // Save the new context for future references.
454     SampleContextFrames NewContext = *Contexts.insert(Context).first;
455     SampleContext FContext(NewContext, RawContext);
456     auto Ret = ProfileMap.emplace(FContext, FunctionSamples());
457     if (WasLeafInlined)
458       FContext.setAttribute(ContextWasInlined);
459     FunctionSamples &FProfile = Ret.first->second;
460     FProfile.setContext(FContext);
461     return Ret.first->second;
462   }
463   return I->second;
464 }
465 
466 void CSProfileGenerator::generateProfile() {
467   FunctionSamples::ProfileIsCS = true;
468 
469   if (Binary->getTrackFuncContextSize())
470     computeSizeForProfiledFunctions();
471 
472   if (Binary->usePseudoProbes()) {
473     // Enable pseudo probe functionalities in SampleProf
474     FunctionSamples::ProfileIsProbeBased = true;
475     generateProbeBasedProfile();
476   } else {
477     generateLineNumBasedProfile();
478   }
479   postProcessProfiles();
480 }
481 
482 void CSProfileGenerator::computeSizeForProfiledFunctions() {
483   // Hash map to deduplicate the function range and the item is a pair of
484   // function start and end offset.
485   std::unordered_map<uint64_t, uint64_t> FuncRanges;
486   // Go through all the ranges in the CS counters, use the start of the range to
487   // look up the function it belongs and record the function range.
488   for (const auto &CI : SampleCounters) {
489     for (auto Item : CI.second.RangeCounter) {
490       // FIXME: Filter the bogus crossing function range.
491       uint64_t RangeStartOffset = Item.first.first;
492       auto FuncRange = Binary->findFuncOffsetRange(RangeStartOffset);
493       if (FuncRange.second != 0)
494         FuncRanges[FuncRange.first] = FuncRange.second;
495     }
496   }
497 
498   for (auto I : FuncRanges) {
499     uint64_t StartOffset = I.first;
500     uint64_t EndOffset = I.second;
501     Binary->computeInlinedContextSizeForRange(StartOffset, EndOffset);
502   }
503 }
504 
505 void CSProfileGenerator::generateLineNumBasedProfile() {
506   for (const auto &CI : SampleCounters) {
507     const StringBasedCtxKey *CtxKey =
508         dyn_cast<StringBasedCtxKey>(CI.first.getPtr());
509     // Get or create function profile for the range
510     FunctionSamples &FunctionProfile =
511         getFunctionProfileForContext(CtxKey->Context, CtxKey->WasLeafInlined);
512 
513     // Fill in function body samples
514     populateBodySamplesForFunction(FunctionProfile, CI.second.RangeCounter);
515     // Fill in boundary sample counts as well as call site samples for calls
516     populateBoundarySamplesForFunction(CtxKey->Context, FunctionProfile,
517                                        CI.second.BranchCounter);
518   }
519   // Fill in call site value sample for inlined calls and also use context to
520   // infer missing samples. Since we don't have call count for inlined
521   // functions, we estimate it from inlinee's profile using the entry of the
522   // body sample.
523   populateInferredFunctionSamples();
524 }
525 
526 void CSProfileGenerator::populateBodySamplesForFunction(
527     FunctionSamples &FunctionProfile, const RangeSample &RangeCounter) {
528   // Compute disjoint ranges first, so we can use MAX
529   // for calculating count for each location.
530   RangeSample Ranges;
531   findDisjointRanges(Ranges, RangeCounter);
532   for (auto Range : Ranges) {
533     uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
534     uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
535     uint64_t Count = Range.second;
536     // Disjoint ranges have introduce zero-filled gap that
537     // doesn't belong to current context, filter them out.
538     if (Count == 0)
539       continue;
540 
541     InstructionPointer IP(Binary, RangeBegin, true);
542     // Disjoint ranges may have range in the middle of two instr,
543     // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
544     // can be Addr1+1 to Addr2-1. We should ignore such range.
545     while (IP.Address <= RangeEnd) {
546       uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
547       auto LeafLoc = Binary->getInlineLeafFrameLoc(Offset);
548       if (LeafLoc.hasValue()) {
549         // Recording body sample for this specific context
550         updateBodySamplesforFunctionProfile(FunctionProfile, *LeafLoc, Count);
551         FunctionProfile.addTotalSamples(Count);
552       }
553 
554       // Move to next IP within the range
555       IP.advance();
556     }
557   }
558 }
559 
560 void CSProfileGenerator::populateBoundarySamplesForFunction(
561     SampleContextFrames ContextId, FunctionSamples &FunctionProfile,
562     const BranchSample &BranchCounters) {
563 
564   for (auto Entry : BranchCounters) {
565     uint64_t SourceOffset = Entry.first.first;
566     uint64_t TargetOffset = Entry.first.second;
567     uint64_t Count = Entry.second;
568     assert(Count != 0 && "Unexpected zero weight branch");
569 
570     StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
571     if (CalleeName.size() == 0)
572       continue;
573 
574     // Record called target sample and its count
575     auto LeafLoc = Binary->getInlineLeafFrameLoc(SourceOffset);
576     if (!LeafLoc.hasValue())
577       continue;
578     FunctionProfile.addCalledTargetSamples(
579         LeafLoc->Location.LineOffset,
580         getBaseDiscriminator(LeafLoc->Location.Discriminator), CalleeName,
581         Count);
582 
583     // Record head sample for called target(callee)
584     SampleContextFrameVector CalleeCtx(ContextId.begin(), ContextId.end());
585     assert(CalleeCtx.back().FuncName == LeafLoc->FuncName &&
586            "Leaf function name doesn't match");
587     CalleeCtx.back() = *LeafLoc;
588     CalleeCtx.emplace_back(CalleeName, LineLocation(0, 0));
589     FunctionSamples &CalleeProfile = getFunctionProfileForContext(CalleeCtx);
590     CalleeProfile.addHeadSamples(Count);
591   }
592 }
593 
594 static SampleContextFrame
595 getCallerContext(SampleContextFrames CalleeContext,
596                  SampleContextFrameVector &CallerContext) {
597   assert(CalleeContext.size() > 1 && "Unexpected empty context");
598   CalleeContext = CalleeContext.drop_back();
599   CallerContext.assign(CalleeContext.begin(), CalleeContext.end());
600   SampleContextFrame CallerFrame = CallerContext.back();
601   CallerContext.back().Location = LineLocation(0, 0);
602   return CallerFrame;
603 }
604 
605 void CSProfileGenerator::populateInferredFunctionSamples() {
606   for (const auto &Item : ProfileMap) {
607     const auto &CalleeContext = Item.first;
608     const FunctionSamples &CalleeProfile = Item.second;
609 
610     // If we already have head sample counts, we must have value profile
611     // for call sites added already. Skip to avoid double counting.
612     if (CalleeProfile.getHeadSamples())
613       continue;
614     // If we don't have context, nothing to do for caller's call site.
615     // This could happen for entry point function.
616     if (CalleeContext.isBaseContext())
617       continue;
618 
619     // Infer Caller's frame loc and context ID through string splitting
620     SampleContextFrameVector CallerContextId;
621     SampleContextFrame &&CallerLeafFrameLoc =
622         getCallerContext(CalleeContext.getContextFrames(), CallerContextId);
623     SampleContextFrames CallerContext(CallerContextId);
624 
625     // It's possible that we haven't seen any sample directly in the caller,
626     // in which case CallerProfile will not exist. But we can't modify
627     // ProfileMap while iterating it.
628     // TODO: created function profile for those callers too
629     if (ProfileMap.find(CallerContext) == ProfileMap.end())
630       continue;
631     FunctionSamples &CallerProfile = ProfileMap[CallerContext];
632 
633     // Since we don't have call count for inlined functions, we
634     // estimate it from inlinee's profile using entry body sample.
635     uint64_t EstimatedCallCount = CalleeProfile.getEntrySamples();
636     // If we don't have samples with location, use 1 to indicate live.
637     if (!EstimatedCallCount && !CalleeProfile.getBodySamples().size())
638       EstimatedCallCount = 1;
639     CallerProfile.addCalledTargetSamples(
640         CallerLeafFrameLoc.Location.LineOffset,
641         CallerLeafFrameLoc.Location.Discriminator,
642         CalleeProfile.getContext().getName(), EstimatedCallCount);
643     CallerProfile.addBodySamples(CallerLeafFrameLoc.Location.LineOffset,
644                                  CallerLeafFrameLoc.Location.Discriminator,
645                                  EstimatedCallCount);
646     CallerProfile.addTotalSamples(EstimatedCallCount);
647   }
648 }
649 
650 void CSProfileGenerator::postProcessProfiles() {
651   // Compute hot/cold threshold based on profile. This will be used for cold
652   // context profile merging/trimming.
653   computeSummaryAndThreshold();
654 
655   // Run global pre-inliner to adjust/merge context profile based on estimated
656   // inline decisions.
657   if (EnableCSPreInliner) {
658     CSPreInliner(ProfileMap, *Binary, HotCountThreshold, ColdCountThreshold)
659         .run();
660   }
661 
662   // Trim and merge cold context profile using cold threshold above. By default,
663   // we skip such merging and trimming when preinliner is on.
664   if (!EnableCSPreInliner || CSProfTrimColdContext.getNumOccurrences() ||
665       CSProfMergeColdContext.getNumOccurrences()) {
666     SampleContextTrimmer(ProfileMap)
667         .trimAndMergeColdContextProfiles(
668             HotCountThreshold, CSProfTrimColdContext, CSProfMergeColdContext,
669             CSProfMaxColdContextDepth);
670   }
671 }
672 
673 void CSProfileGenerator::computeSummaryAndThreshold() {
674   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
675   auto Summary = Builder.computeSummaryForProfiles(ProfileMap);
676   HotCountThreshold = ProfileSummaryBuilder::getHotCountThreshold(
677       (Summary->getDetailedSummary()));
678   ColdCountThreshold = ProfileSummaryBuilder::getColdCountThreshold(
679       (Summary->getDetailedSummary()));
680 }
681 
682 // Helper function to extract context prefix string stack
683 // Extract context stack for reusing, leaf context stack will
684 // be added compressed while looking up function profile
685 static void extractPrefixContextStack(
686     SampleContextFrameVector &ContextStack,
687     const SmallVectorImpl<const MCDecodedPseudoProbe *> &Probes,
688     ProfiledBinary *Binary) {
689   for (const auto *P : Probes) {
690     Binary->getInlineContextForProbe(P, ContextStack, true);
691   }
692 }
693 
694 void CSProfileGenerator::generateProbeBasedProfile() {
695   for (const auto &CI : SampleCounters) {
696     const ProbeBasedCtxKey *CtxKey =
697         dyn_cast<ProbeBasedCtxKey>(CI.first.getPtr());
698     SampleContextFrameVector ContextStack;
699     extractPrefixContextStack(ContextStack, CtxKey->Probes, Binary);
700     // Fill in function body samples from probes, also infer caller's samples
701     // from callee's probe
702     populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStack);
703     // Fill in boundary samples for a call probe
704     populateBoundarySamplesWithProbes(CI.second.BranchCounter, ContextStack);
705   }
706 }
707 
708 void CSProfileGenerator::extractProbesFromRange(const RangeSample &RangeCounter,
709                                                 ProbeCounterMap &ProbeCounter) {
710   RangeSample Ranges;
711   findDisjointRanges(Ranges, RangeCounter);
712   for (const auto &Range : Ranges) {
713     uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
714     uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
715     uint64_t Count = Range.second;
716     // Disjoint ranges have introduce zero-filled gap that
717     // doesn't belong to current context, filter them out.
718     if (Count == 0)
719       continue;
720 
721     InstructionPointer IP(Binary, RangeBegin, true);
722 
723     // Disjoint ranges may have range in the middle of two instr,
724     // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
725     // can be Addr1+1 to Addr2-1. We should ignore such range.
726     if (IP.Address > RangeEnd)
727       continue;
728 
729     while (IP.Address <= RangeEnd) {
730       const AddressProbesMap &Address2ProbesMap =
731           Binary->getAddress2ProbesMap();
732       auto It = Address2ProbesMap.find(IP.Address);
733       if (It != Address2ProbesMap.end()) {
734         for (const auto &Probe : It->second) {
735           if (!Probe.isBlock())
736             continue;
737           ProbeCounter[&Probe] += Count;
738         }
739       }
740 
741       IP.advance();
742     }
743   }
744 }
745 
746 void CSProfileGenerator::populateBodySamplesWithProbes(
747     const RangeSample &RangeCounter, SampleContextFrames ContextStack) {
748   ProbeCounterMap ProbeCounter;
749   // Extract the top frame probes by looking up each address among the range in
750   // the Address2ProbeMap
751   extractProbesFromRange(RangeCounter, ProbeCounter);
752   std::unordered_map<MCDecodedPseudoProbeInlineTree *,
753                      std::unordered_set<FunctionSamples *>>
754       FrameSamples;
755   for (auto PI : ProbeCounter) {
756     const MCDecodedPseudoProbe *Probe = PI.first;
757     uint64_t Count = PI.second;
758     FunctionSamples &FunctionProfile =
759         getFunctionProfileForLeafProbe(ContextStack, Probe);
760     // Record the current frame and FunctionProfile whenever samples are
761     // collected for non-danglie probes. This is for reporting all of the
762     // zero count probes of the frame later.
763     FrameSamples[Probe->getInlineTreeNode()].insert(&FunctionProfile);
764     FunctionProfile.addBodySamplesForProbe(Probe->getIndex(), Count);
765     FunctionProfile.addTotalSamples(Count);
766     if (Probe->isEntry()) {
767       FunctionProfile.addHeadSamples(Count);
768       // Look up for the caller's function profile
769       const auto *InlinerDesc = Binary->getInlinerDescForProbe(Probe);
770       if (InlinerDesc != nullptr) {
771         // Since the context id will be compressed, we have to use callee's
772         // context id to infer caller's context id to ensure they share the
773         // same context prefix.
774         SampleContextFrames CalleeContextId =
775             FunctionProfile.getContext().getContextFrames();
776         SampleContextFrameVector CallerContextId;
777         SampleContextFrame &&CallerLeafFrameLoc =
778             getCallerContext(CalleeContextId, CallerContextId);
779         uint64_t CallerIndex = CallerLeafFrameLoc.Location.LineOffset;
780         assert(CallerIndex &&
781                "Inferred caller's location index shouldn't be zero!");
782         FunctionSamples &CallerProfile =
783             getFunctionProfileForContext(CallerContextId);
784         CallerProfile.setFunctionHash(InlinerDesc->FuncHash);
785         CallerProfile.addBodySamples(CallerIndex, 0, Count);
786         CallerProfile.addTotalSamples(Count);
787         CallerProfile.addCalledTargetSamples(
788             CallerIndex, 0, FunctionProfile.getContext().getName(), Count);
789       }
790     }
791   }
792 
793   // Assign zero count for remaining probes without sample hits to
794   // differentiate from probes optimized away, of which the counts are unknown
795   // and will be inferred by the compiler.
796   for (auto &I : FrameSamples) {
797     for (auto *FunctionProfile : I.second) {
798       for (auto *Probe : I.first->getProbes()) {
799         FunctionProfile->addBodySamplesForProbe(Probe->getIndex(), 0);
800       }
801     }
802   }
803 }
804 
805 void CSProfileGenerator::populateBoundarySamplesWithProbes(
806     const BranchSample &BranchCounter, SampleContextFrames ContextStack) {
807   for (auto BI : BranchCounter) {
808     uint64_t SourceOffset = BI.first.first;
809     uint64_t TargetOffset = BI.first.second;
810     uint64_t Count = BI.second;
811     uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset);
812     const MCDecodedPseudoProbe *CallProbe =
813         Binary->getCallProbeForAddr(SourceAddress);
814     if (CallProbe == nullptr)
815       continue;
816     FunctionSamples &FunctionProfile =
817         getFunctionProfileForLeafProbe(ContextStack, CallProbe);
818     FunctionProfile.addBodySamples(CallProbe->getIndex(), 0, Count);
819     FunctionProfile.addTotalSamples(Count);
820     StringRef CalleeName = getCalleeNameForOffset(TargetOffset);
821     if (CalleeName.size() == 0)
822       continue;
823     FunctionProfile.addCalledTargetSamples(CallProbe->getIndex(), 0, CalleeName,
824                                            Count);
825   }
826 }
827 
828 FunctionSamples &CSProfileGenerator::getFunctionProfileForLeafProbe(
829     SampleContextFrames ContextStack, const MCDecodedPseudoProbe *LeafProbe) {
830 
831   // Explicitly copy the context for appending the leaf context
832   SampleContextFrameVector NewContextStack(ContextStack.begin(),
833                                            ContextStack.end());
834   Binary->getInlineContextForProbe(LeafProbe, NewContextStack, true);
835   // For leaf inlined context with the top frame, we should strip off the top
836   // frame's probe id, like:
837   // Inlined stack: [foo:1, bar:2], the ContextId will be "foo:1 @ bar"
838   auto LeafFrame = NewContextStack.back();
839   LeafFrame.Location = LineLocation(0, 0);
840   NewContextStack.pop_back();
841   // Compress the context string except for the leaf frame
842   CSProfileGenerator::compressRecursionContext(NewContextStack);
843   CSProfileGenerator::trimContext(NewContextStack);
844   NewContextStack.push_back(LeafFrame);
845 
846   const auto *FuncDesc = Binary->getFuncDescForGUID(LeafProbe->getGuid());
847   bool WasLeafInlined = LeafProbe->getInlineTreeNode()->hasInlineSite();
848   FunctionSamples &FunctionProile =
849       getFunctionProfileForContext(NewContextStack, WasLeafInlined);
850   FunctionProile.setFunctionHash(FuncDesc->FuncHash);
851   return FunctionProile;
852 }
853 
854 } // end namespace sampleprof
855 } // end namespace llvm
856