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