1*7397905aSRong Xu //===- SampleProfileLoaderBaseUtil.cpp - Profile loader Util func ---------===//
2*7397905aSRong Xu //
3*7397905aSRong Xu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7397905aSRong Xu // See https://llvm.org/LICENSE.txt for license information.
5*7397905aSRong Xu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7397905aSRong Xu //
7*7397905aSRong Xu //===----------------------------------------------------------------------===//
8*7397905aSRong Xu //
9*7397905aSRong Xu // This file implements the SampleProfileLoader base utility functions.
10*7397905aSRong Xu //
11*7397905aSRong Xu //===----------------------------------------------------------------------===//
12*7397905aSRong Xu 
13*7397905aSRong Xu #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"
14*7397905aSRong Xu 
15*7397905aSRong Xu namespace llvm {
16*7397905aSRong Xu 
17*7397905aSRong Xu cl::opt<unsigned> SampleProfileMaxPropagateIterations(
18*7397905aSRong Xu     "sample-profile-max-propagate-iterations", cl::init(100),
19*7397905aSRong Xu     cl::desc("Maximum number of iterations to go through when propagating "
20*7397905aSRong Xu              "sample block/edge weights through the CFG."));
21*7397905aSRong Xu 
22*7397905aSRong Xu cl::opt<unsigned> SampleProfileRecordCoverage(
23*7397905aSRong Xu     "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"),
24*7397905aSRong Xu     cl::desc("Emit a warning if less than N% of records in the input profile "
25*7397905aSRong Xu              "are matched to the IR."));
26*7397905aSRong Xu 
27*7397905aSRong Xu cl::opt<unsigned> SampleProfileSampleCoverage(
28*7397905aSRong Xu     "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"),
29*7397905aSRong Xu     cl::desc("Emit a warning if less than N% of samples in the input profile "
30*7397905aSRong Xu              "are matched to the IR."));
31*7397905aSRong Xu 
32*7397905aSRong Xu cl::opt<bool> NoWarnSampleUnused(
33*7397905aSRong Xu     "no-warn-sample-unused", cl::init(false), cl::Hidden,
34*7397905aSRong Xu     cl::desc("Use this option to turn off/on warnings about function with "
35*7397905aSRong Xu              "samples but without debug information to use those samples. "));
36*7397905aSRong Xu 
37*7397905aSRong Xu namespace sampleprofutil {
38*7397905aSRong Xu 
39*7397905aSRong Xu /// Return true if the given callsite is hot wrt to hot cutoff threshold.
40*7397905aSRong Xu ///
41*7397905aSRong Xu /// Functions that were inlined in the original binary will be represented
42*7397905aSRong Xu /// in the inline stack in the sample profile. If the profile shows that
43*7397905aSRong Xu /// the original inline decision was "good" (i.e., the callsite is executed
44*7397905aSRong Xu /// frequently), then we will recreate the inline decision and apply the
45*7397905aSRong Xu /// profile from the inlined callsite.
46*7397905aSRong Xu ///
47*7397905aSRong Xu /// To decide whether an inlined callsite is hot, we compare the callsite
48*7397905aSRong Xu /// sample count with the hot cutoff computed by ProfileSummaryInfo, it is
49*7397905aSRong Xu /// regarded as hot if the count is above the cutoff value.
50*7397905aSRong Xu ///
51*7397905aSRong Xu /// When ProfileAccurateForSymsInList is enabled and profile symbol list
52*7397905aSRong Xu /// is present, functions in the profile symbol list but without profile will
53*7397905aSRong Xu /// be regarded as cold and much less inlining will happen in CGSCC inlining
54*7397905aSRong Xu /// pass, so we tend to lower the hot criteria here to allow more early
55*7397905aSRong Xu /// inlining to happen for warm callsites and it is helpful for performance.
56*7397905aSRong Xu bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI,
57*7397905aSRong Xu                    bool ProfAccForSymsInList) {
58*7397905aSRong Xu   if (!CallsiteFS)
59*7397905aSRong Xu     return false; // The callsite was not inlined in the original binary.
60*7397905aSRong Xu 
61*7397905aSRong Xu   assert(PSI && "PSI is expected to be non null");
62*7397905aSRong Xu   uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples();
63*7397905aSRong Xu   if (ProfAccForSymsInList)
64*7397905aSRong Xu     return !PSI->isColdCount(CallsiteTotalSamples);
65*7397905aSRong Xu   else
66*7397905aSRong Xu     return PSI->isHotCount(CallsiteTotalSamples);
67*7397905aSRong Xu }
68*7397905aSRong Xu 
69*7397905aSRong Xu /// Mark as used the sample record for the given function samples at
70*7397905aSRong Xu /// (LineOffset, Discriminator).
71*7397905aSRong Xu ///
72*7397905aSRong Xu /// \returns true if this is the first time we mark the given record.
73*7397905aSRong Xu bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS,
74*7397905aSRong Xu                                             uint32_t LineOffset,
75*7397905aSRong Xu                                             uint32_t Discriminator,
76*7397905aSRong Xu                                             uint64_t Samples) {
77*7397905aSRong Xu   LineLocation Loc(LineOffset, Discriminator);
78*7397905aSRong Xu   unsigned &Count = SampleCoverage[FS][Loc];
79*7397905aSRong Xu   bool FirstTime = (++Count == 1);
80*7397905aSRong Xu   if (FirstTime)
81*7397905aSRong Xu     TotalUsedSamples += Samples;
82*7397905aSRong Xu   return FirstTime;
83*7397905aSRong Xu }
84*7397905aSRong Xu 
85*7397905aSRong Xu /// Return the number of sample records that were applied from this profile.
86*7397905aSRong Xu ///
87*7397905aSRong Xu /// This count does not include records from cold inlined callsites.
88*7397905aSRong Xu unsigned
89*7397905aSRong Xu SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS,
90*7397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
91*7397905aSRong Xu   auto I = SampleCoverage.find(FS);
92*7397905aSRong Xu 
93*7397905aSRong Xu   // The size of the coverage map for FS represents the number of records
94*7397905aSRong Xu   // that were marked used at least once.
95*7397905aSRong Xu   unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0;
96*7397905aSRong Xu 
97*7397905aSRong Xu   // If there are inlined callsites in this function, count the samples found
98*7397905aSRong Xu   // in the respective bodies. However, do not bother counting callees with 0
99*7397905aSRong Xu   // total samples, these are callees that were never invoked at runtime.
100*7397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
101*7397905aSRong Xu     for (const auto &J : I.second) {
102*7397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
103*7397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
104*7397905aSRong Xu         Count += countUsedRecords(CalleeSamples, PSI);
105*7397905aSRong Xu     }
106*7397905aSRong Xu 
107*7397905aSRong Xu   return Count;
108*7397905aSRong Xu }
109*7397905aSRong Xu 
110*7397905aSRong Xu /// Return the number of sample records in the body of this profile.
111*7397905aSRong Xu ///
112*7397905aSRong Xu /// This count does not include records from cold inlined callsites.
113*7397905aSRong Xu unsigned
114*7397905aSRong Xu SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS,
115*7397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
116*7397905aSRong Xu   unsigned Count = FS->getBodySamples().size();
117*7397905aSRong Xu 
118*7397905aSRong Xu   // Only count records in hot callsites.
119*7397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
120*7397905aSRong Xu     for (const auto &J : I.second) {
121*7397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
122*7397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
123*7397905aSRong Xu         Count += countBodyRecords(CalleeSamples, PSI);
124*7397905aSRong Xu     }
125*7397905aSRong Xu 
126*7397905aSRong Xu   return Count;
127*7397905aSRong Xu }
128*7397905aSRong Xu 
129*7397905aSRong Xu /// Return the number of samples collected in the body of this profile.
130*7397905aSRong Xu ///
131*7397905aSRong Xu /// This count does not include samples from cold inlined callsites.
132*7397905aSRong Xu uint64_t
133*7397905aSRong Xu SampleCoverageTracker::countBodySamples(const FunctionSamples *FS,
134*7397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
135*7397905aSRong Xu   uint64_t Total = 0;
136*7397905aSRong Xu   for (const auto &I : FS->getBodySamples())
137*7397905aSRong Xu     Total += I.second.getSamples();
138*7397905aSRong Xu 
139*7397905aSRong Xu   // Only count samples in hot callsites.
140*7397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
141*7397905aSRong Xu     for (const auto &J : I.second) {
142*7397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
143*7397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
144*7397905aSRong Xu         Total += countBodySamples(CalleeSamples, PSI);
145*7397905aSRong Xu     }
146*7397905aSRong Xu 
147*7397905aSRong Xu   return Total;
148*7397905aSRong Xu }
149*7397905aSRong Xu 
150*7397905aSRong Xu /// Return the fraction of sample records used in this profile.
151*7397905aSRong Xu ///
152*7397905aSRong Xu /// The returned value is an unsigned integer in the range 0-100 indicating
153*7397905aSRong Xu /// the percentage of sample records that were used while applying this
154*7397905aSRong Xu /// profile to the associated function.
155*7397905aSRong Xu unsigned SampleCoverageTracker::computeCoverage(unsigned Used,
156*7397905aSRong Xu                                                 unsigned Total) const {
157*7397905aSRong Xu   assert(Used <= Total &&
158*7397905aSRong Xu          "number of used records cannot exceed the total number of records");
159*7397905aSRong Xu   return Total > 0 ? Used * 100 / Total : 100;
160*7397905aSRong Xu }
161*7397905aSRong Xu 
162*7397905aSRong Xu } // end of namespace sampleprofutil
163*7397905aSRong Xu } // end of namespace llvm
164