xref: /llvm-project/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp (revision 61eb12e1f423063b0ead944827dc53b02baed0d4)
17397905aSRong Xu //===- SampleProfileLoaderBaseUtil.cpp - Profile loader Util func ---------===//
27397905aSRong Xu //
37397905aSRong Xu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47397905aSRong Xu // See https://llvm.org/LICENSE.txt for license information.
57397905aSRong Xu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67397905aSRong Xu //
77397905aSRong Xu //===----------------------------------------------------------------------===//
87397905aSRong Xu //
97397905aSRong Xu // This file implements the SampleProfileLoader base utility functions.
107397905aSRong Xu //
117397905aSRong Xu //===----------------------------------------------------------------------===//
127397905aSRong Xu 
137397905aSRong Xu #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"
14a494ae43Sserge-sans-paille #include "llvm/Analysis/ProfileSummaryInfo.h"
15a494ae43Sserge-sans-paille #include "llvm/IR/Constants.h"
16a494ae43Sserge-sans-paille #include "llvm/IR/Module.h"
17a494ae43Sserge-sans-paille #include "llvm/Transforms/Utils/ModuleUtils.h"
187397905aSRong Xu 
197397905aSRong Xu namespace llvm {
207397905aSRong Xu 
217397905aSRong Xu cl::opt<unsigned> SampleProfileMaxPropagateIterations(
227397905aSRong Xu     "sample-profile-max-propagate-iterations", cl::init(100),
237397905aSRong Xu     cl::desc("Maximum number of iterations to go through when propagating "
247397905aSRong Xu              "sample block/edge weights through the CFG."));
257397905aSRong Xu 
267397905aSRong Xu cl::opt<unsigned> SampleProfileRecordCoverage(
277397905aSRong Xu     "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"),
287397905aSRong Xu     cl::desc("Emit a warning if less than N% of records in the input profile "
297397905aSRong Xu              "are matched to the IR."));
307397905aSRong Xu 
317397905aSRong Xu cl::opt<unsigned> SampleProfileSampleCoverage(
327397905aSRong Xu     "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"),
337397905aSRong Xu     cl::desc("Emit a warning if less than N% of samples in the input profile "
347397905aSRong Xu              "are matched to the IR."));
357397905aSRong Xu 
367397905aSRong Xu cl::opt<bool> NoWarnSampleUnused(
377397905aSRong Xu     "no-warn-sample-unused", cl::init(false), cl::Hidden,
387397905aSRong Xu     cl::desc("Use this option to turn off/on warnings about function with "
397397905aSRong Xu              "samples but without debug information to use those samples. "));
407397905aSRong Xu 
417cc2493dSspupyrev cl::opt<bool> SampleProfileUseProfi(
42*557efc9aSFangrui Song     "sample-profile-use-profi", cl::Hidden,
437cc2493dSspupyrev     cl::desc("Use profi to infer block and edge counts."));
447cc2493dSspupyrev 
457397905aSRong Xu namespace sampleprofutil {
467397905aSRong Xu 
477397905aSRong Xu /// Return true if the given callsite is hot wrt to hot cutoff threshold.
487397905aSRong Xu ///
497397905aSRong Xu /// Functions that were inlined in the original binary will be represented
507397905aSRong Xu /// in the inline stack in the sample profile. If the profile shows that
517397905aSRong Xu /// the original inline decision was "good" (i.e., the callsite is executed
527397905aSRong Xu /// frequently), then we will recreate the inline decision and apply the
537397905aSRong Xu /// profile from the inlined callsite.
547397905aSRong Xu ///
557397905aSRong Xu /// To decide whether an inlined callsite is hot, we compare the callsite
567397905aSRong Xu /// sample count with the hot cutoff computed by ProfileSummaryInfo, it is
577397905aSRong Xu /// regarded as hot if the count is above the cutoff value.
587397905aSRong Xu ///
597397905aSRong Xu /// When ProfileAccurateForSymsInList is enabled and profile symbol list
607397905aSRong Xu /// is present, functions in the profile symbol list but without profile will
617397905aSRong Xu /// be regarded as cold and much less inlining will happen in CGSCC inlining
627397905aSRong Xu /// pass, so we tend to lower the hot criteria here to allow more early
637397905aSRong Xu /// inlining to happen for warm callsites and it is helpful for performance.
callsiteIsHot(const FunctionSamples * CallsiteFS,ProfileSummaryInfo * PSI,bool ProfAccForSymsInList)647397905aSRong Xu bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI,
657397905aSRong Xu                    bool ProfAccForSymsInList) {
667397905aSRong Xu   if (!CallsiteFS)
677397905aSRong Xu     return false; // The callsite was not inlined in the original binary.
687397905aSRong Xu 
697397905aSRong Xu   assert(PSI && "PSI is expected to be non null");
707397905aSRong Xu   uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples();
717397905aSRong Xu   if (ProfAccForSymsInList)
727397905aSRong Xu     return !PSI->isColdCount(CallsiteTotalSamples);
737397905aSRong Xu   else
747397905aSRong Xu     return PSI->isHotCount(CallsiteTotalSamples);
757397905aSRong Xu }
767397905aSRong Xu 
777397905aSRong Xu /// Mark as used the sample record for the given function samples at
787397905aSRong Xu /// (LineOffset, Discriminator).
797397905aSRong Xu ///
807397905aSRong Xu /// \returns true if this is the first time we mark the given record.
markSamplesUsed(const FunctionSamples * FS,uint32_t LineOffset,uint32_t Discriminator,uint64_t Samples)817397905aSRong Xu bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS,
827397905aSRong Xu                                             uint32_t LineOffset,
837397905aSRong Xu                                             uint32_t Discriminator,
847397905aSRong Xu                                             uint64_t Samples) {
857397905aSRong Xu   LineLocation Loc(LineOffset, Discriminator);
867397905aSRong Xu   unsigned &Count = SampleCoverage[FS][Loc];
877397905aSRong Xu   bool FirstTime = (++Count == 1);
887397905aSRong Xu   if (FirstTime)
897397905aSRong Xu     TotalUsedSamples += Samples;
907397905aSRong Xu   return FirstTime;
917397905aSRong Xu }
927397905aSRong Xu 
937397905aSRong Xu /// Return the number of sample records that were applied from this profile.
947397905aSRong Xu ///
957397905aSRong Xu /// This count does not include records from cold inlined callsites.
967397905aSRong Xu unsigned
countUsedRecords(const FunctionSamples * FS,ProfileSummaryInfo * PSI) const977397905aSRong Xu SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS,
987397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
997397905aSRong Xu   auto I = SampleCoverage.find(FS);
1007397905aSRong Xu 
1017397905aSRong Xu   // The size of the coverage map for FS represents the number of records
1027397905aSRong Xu   // that were marked used at least once.
1037397905aSRong Xu   unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0;
1047397905aSRong Xu 
1057397905aSRong Xu   // If there are inlined callsites in this function, count the samples found
1067397905aSRong Xu   // in the respective bodies. However, do not bother counting callees with 0
1077397905aSRong Xu   // total samples, these are callees that were never invoked at runtime.
1087397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
1097397905aSRong Xu     for (const auto &J : I.second) {
1107397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
1117397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
1127397905aSRong Xu         Count += countUsedRecords(CalleeSamples, PSI);
1137397905aSRong Xu     }
1147397905aSRong Xu 
1157397905aSRong Xu   return Count;
1167397905aSRong Xu }
1177397905aSRong Xu 
1187397905aSRong Xu /// Return the number of sample records in the body of this profile.
1197397905aSRong Xu ///
1207397905aSRong Xu /// This count does not include records from cold inlined callsites.
1217397905aSRong Xu unsigned
countBodyRecords(const FunctionSamples * FS,ProfileSummaryInfo * PSI) const1227397905aSRong Xu SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS,
1237397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
1247397905aSRong Xu   unsigned Count = FS->getBodySamples().size();
1257397905aSRong Xu 
1267397905aSRong Xu   // Only count records in hot callsites.
1277397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
1287397905aSRong Xu     for (const auto &J : I.second) {
1297397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
1307397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
1317397905aSRong Xu         Count += countBodyRecords(CalleeSamples, PSI);
1327397905aSRong Xu     }
1337397905aSRong Xu 
1347397905aSRong Xu   return Count;
1357397905aSRong Xu }
1367397905aSRong Xu 
1377397905aSRong Xu /// Return the number of samples collected in the body of this profile.
1387397905aSRong Xu ///
1397397905aSRong Xu /// This count does not include samples from cold inlined callsites.
1407397905aSRong Xu uint64_t
countBodySamples(const FunctionSamples * FS,ProfileSummaryInfo * PSI) const1417397905aSRong Xu SampleCoverageTracker::countBodySamples(const FunctionSamples *FS,
1427397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
1437397905aSRong Xu   uint64_t Total = 0;
1447397905aSRong Xu   for (const auto &I : FS->getBodySamples())
1457397905aSRong Xu     Total += I.second.getSamples();
1467397905aSRong Xu 
1477397905aSRong Xu   // Only count samples in hot callsites.
1487397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
1497397905aSRong Xu     for (const auto &J : I.second) {
1507397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
1517397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
1527397905aSRong Xu         Total += countBodySamples(CalleeSamples, PSI);
1537397905aSRong Xu     }
1547397905aSRong Xu 
1557397905aSRong Xu   return Total;
1567397905aSRong Xu }
1577397905aSRong Xu 
1587397905aSRong Xu /// Return the fraction of sample records used in this profile.
1597397905aSRong Xu ///
1607397905aSRong Xu /// The returned value is an unsigned integer in the range 0-100 indicating
1617397905aSRong Xu /// the percentage of sample records that were used while applying this
1627397905aSRong Xu /// profile to the associated function.
computeCoverage(unsigned Used,unsigned Total) const1637397905aSRong Xu unsigned SampleCoverageTracker::computeCoverage(unsigned Used,
1647397905aSRong Xu                                                 unsigned Total) const {
1657397905aSRong Xu   assert(Used <= Total &&
1667397905aSRong Xu          "number of used records cannot exceed the total number of records");
1677397905aSRong Xu   return Total > 0 ? Used * 100 / Total : 100;
1687397905aSRong Xu }
1697397905aSRong Xu 
17082a0bb1aSRong Xu /// Create a global variable to flag FSDiscriminators are used.
createFSDiscriminatorVariable(Module * M)17182a0bb1aSRong Xu void createFSDiscriminatorVariable(Module *M) {
17282a0bb1aSRong Xu   const char *FSDiscriminatorVar = "__llvm_fs_discriminator__";
17382a0bb1aSRong Xu   if (M->getGlobalVariable(FSDiscriminatorVar))
17482a0bb1aSRong Xu     return;
17582a0bb1aSRong Xu 
17682a0bb1aSRong Xu   auto &Context = M->getContext();
17782a0bb1aSRong Xu   // Place this variable to llvm.used so it won't be GC'ed.
17882a0bb1aSRong Xu   appendToUsed(*M, {new GlobalVariable(*M, Type::getInt1Ty(Context), true,
17982a0bb1aSRong Xu                                        GlobalValue::WeakODRLinkage,
18082a0bb1aSRong Xu                                        ConstantInt::getTrue(Context),
18182a0bb1aSRong Xu                                        FSDiscriminatorVar)});
18282a0bb1aSRong Xu }
18382a0bb1aSRong Xu 
1847397905aSRong Xu } // end of namespace sampleprofutil
1857397905aSRong Xu } // end of namespace llvm
186