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"
147397905aSRong Xu 
157397905aSRong Xu namespace llvm {
167397905aSRong Xu 
177397905aSRong Xu cl::opt<unsigned> SampleProfileMaxPropagateIterations(
187397905aSRong Xu     "sample-profile-max-propagate-iterations", cl::init(100),
197397905aSRong Xu     cl::desc("Maximum number of iterations to go through when propagating "
207397905aSRong Xu              "sample block/edge weights through the CFG."));
217397905aSRong Xu 
227397905aSRong Xu cl::opt<unsigned> SampleProfileRecordCoverage(
237397905aSRong Xu     "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"),
247397905aSRong Xu     cl::desc("Emit a warning if less than N% of records in the input profile "
257397905aSRong Xu              "are matched to the IR."));
267397905aSRong Xu 
277397905aSRong Xu cl::opt<unsigned> SampleProfileSampleCoverage(
287397905aSRong Xu     "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"),
297397905aSRong Xu     cl::desc("Emit a warning if less than N% of samples in the input profile "
307397905aSRong Xu              "are matched to the IR."));
317397905aSRong Xu 
327397905aSRong Xu cl::opt<bool> NoWarnSampleUnused(
337397905aSRong Xu     "no-warn-sample-unused", cl::init(false), cl::Hidden,
347397905aSRong Xu     cl::desc("Use this option to turn off/on warnings about function with "
357397905aSRong Xu              "samples but without debug information to use those samples. "));
367397905aSRong Xu 
377397905aSRong Xu namespace sampleprofutil {
387397905aSRong Xu 
397397905aSRong Xu /// Return true if the given callsite is hot wrt to hot cutoff threshold.
407397905aSRong Xu ///
417397905aSRong Xu /// Functions that were inlined in the original binary will be represented
427397905aSRong Xu /// in the inline stack in the sample profile. If the profile shows that
437397905aSRong Xu /// the original inline decision was "good" (i.e., the callsite is executed
447397905aSRong Xu /// frequently), then we will recreate the inline decision and apply the
457397905aSRong Xu /// profile from the inlined callsite.
467397905aSRong Xu ///
477397905aSRong Xu /// To decide whether an inlined callsite is hot, we compare the callsite
487397905aSRong Xu /// sample count with the hot cutoff computed by ProfileSummaryInfo, it is
497397905aSRong Xu /// regarded as hot if the count is above the cutoff value.
507397905aSRong Xu ///
517397905aSRong Xu /// When ProfileAccurateForSymsInList is enabled and profile symbol list
527397905aSRong Xu /// is present, functions in the profile symbol list but without profile will
537397905aSRong Xu /// be regarded as cold and much less inlining will happen in CGSCC inlining
547397905aSRong Xu /// pass, so we tend to lower the hot criteria here to allow more early
557397905aSRong Xu /// inlining to happen for warm callsites and it is helpful for performance.
567397905aSRong Xu bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI,
577397905aSRong Xu                    bool ProfAccForSymsInList) {
587397905aSRong Xu   if (!CallsiteFS)
597397905aSRong Xu     return false; // The callsite was not inlined in the original binary.
607397905aSRong Xu 
617397905aSRong Xu   assert(PSI && "PSI is expected to be non null");
627397905aSRong Xu   uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples();
637397905aSRong Xu   if (ProfAccForSymsInList)
647397905aSRong Xu     return !PSI->isColdCount(CallsiteTotalSamples);
657397905aSRong Xu   else
667397905aSRong Xu     return PSI->isHotCount(CallsiteTotalSamples);
677397905aSRong Xu }
687397905aSRong Xu 
697397905aSRong Xu /// Mark as used the sample record for the given function samples at
707397905aSRong Xu /// (LineOffset, Discriminator).
717397905aSRong Xu ///
727397905aSRong Xu /// \returns true if this is the first time we mark the given record.
737397905aSRong Xu bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS,
747397905aSRong Xu                                             uint32_t LineOffset,
757397905aSRong Xu                                             uint32_t Discriminator,
767397905aSRong Xu                                             uint64_t Samples) {
777397905aSRong Xu   LineLocation Loc(LineOffset, Discriminator);
787397905aSRong Xu   unsigned &Count = SampleCoverage[FS][Loc];
797397905aSRong Xu   bool FirstTime = (++Count == 1);
807397905aSRong Xu   if (FirstTime)
817397905aSRong Xu     TotalUsedSamples += Samples;
827397905aSRong Xu   return FirstTime;
837397905aSRong Xu }
847397905aSRong Xu 
857397905aSRong Xu /// Return the number of sample records that were applied from this profile.
867397905aSRong Xu ///
877397905aSRong Xu /// This count does not include records from cold inlined callsites.
887397905aSRong Xu unsigned
897397905aSRong Xu SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS,
907397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
917397905aSRong Xu   auto I = SampleCoverage.find(FS);
927397905aSRong Xu 
937397905aSRong Xu   // The size of the coverage map for FS represents the number of records
947397905aSRong Xu   // that were marked used at least once.
957397905aSRong Xu   unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0;
967397905aSRong Xu 
977397905aSRong Xu   // If there are inlined callsites in this function, count the samples found
987397905aSRong Xu   // in the respective bodies. However, do not bother counting callees with 0
997397905aSRong Xu   // total samples, these are callees that were never invoked at runtime.
1007397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
1017397905aSRong Xu     for (const auto &J : I.second) {
1027397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
1037397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
1047397905aSRong Xu         Count += countUsedRecords(CalleeSamples, PSI);
1057397905aSRong Xu     }
1067397905aSRong Xu 
1077397905aSRong Xu   return Count;
1087397905aSRong Xu }
1097397905aSRong Xu 
1107397905aSRong Xu /// Return the number of sample records in the body of this profile.
1117397905aSRong Xu ///
1127397905aSRong Xu /// This count does not include records from cold inlined callsites.
1137397905aSRong Xu unsigned
1147397905aSRong Xu SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS,
1157397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
1167397905aSRong Xu   unsigned Count = FS->getBodySamples().size();
1177397905aSRong Xu 
1187397905aSRong Xu   // Only count records in hot callsites.
1197397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
1207397905aSRong Xu     for (const auto &J : I.second) {
1217397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
1227397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
1237397905aSRong Xu         Count += countBodyRecords(CalleeSamples, PSI);
1247397905aSRong Xu     }
1257397905aSRong Xu 
1267397905aSRong Xu   return Count;
1277397905aSRong Xu }
1287397905aSRong Xu 
1297397905aSRong Xu /// Return the number of samples collected in the body of this profile.
1307397905aSRong Xu ///
1317397905aSRong Xu /// This count does not include samples from cold inlined callsites.
1327397905aSRong Xu uint64_t
1337397905aSRong Xu SampleCoverageTracker::countBodySamples(const FunctionSamples *FS,
1347397905aSRong Xu                                         ProfileSummaryInfo *PSI) const {
1357397905aSRong Xu   uint64_t Total = 0;
1367397905aSRong Xu   for (const auto &I : FS->getBodySamples())
1377397905aSRong Xu     Total += I.second.getSamples();
1387397905aSRong Xu 
1397397905aSRong Xu   // Only count samples in hot callsites.
1407397905aSRong Xu   for (const auto &I : FS->getCallsiteSamples())
1417397905aSRong Xu     for (const auto &J : I.second) {
1427397905aSRong Xu       const FunctionSamples *CalleeSamples = &J.second;
1437397905aSRong Xu       if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))
1447397905aSRong Xu         Total += countBodySamples(CalleeSamples, PSI);
1457397905aSRong Xu     }
1467397905aSRong Xu 
1477397905aSRong Xu   return Total;
1487397905aSRong Xu }
1497397905aSRong Xu 
1507397905aSRong Xu /// Return the fraction of sample records used in this profile.
1517397905aSRong Xu ///
1527397905aSRong Xu /// The returned value is an unsigned integer in the range 0-100 indicating
1537397905aSRong Xu /// the percentage of sample records that were used while applying this
1547397905aSRong Xu /// profile to the associated function.
1557397905aSRong Xu unsigned SampleCoverageTracker::computeCoverage(unsigned Used,
1567397905aSRong Xu                                                 unsigned Total) const {
1577397905aSRong Xu   assert(Used <= Total &&
1587397905aSRong Xu          "number of used records cannot exceed the total number of records");
1597397905aSRong Xu   return Total > 0 ? Used * 100 / Total : 100;
1607397905aSRong Xu }
1617397905aSRong Xu 
162*82a0bb1aSRong Xu /// Create a global variable to flag FSDiscriminators are used.
163*82a0bb1aSRong Xu void createFSDiscriminatorVariable(Module *M) {
164*82a0bb1aSRong Xu   const char *FSDiscriminatorVar = "__llvm_fs_discriminator__";
165*82a0bb1aSRong Xu   if (M->getGlobalVariable(FSDiscriminatorVar))
166*82a0bb1aSRong Xu     return;
167*82a0bb1aSRong Xu 
168*82a0bb1aSRong Xu   auto &Context = M->getContext();
169*82a0bb1aSRong Xu   // Place this variable to llvm.used so it won't be GC'ed.
170*82a0bb1aSRong Xu   appendToUsed(*M, {new GlobalVariable(*M, Type::getInt1Ty(Context), true,
171*82a0bb1aSRong Xu                                        GlobalValue::WeakODRLinkage,
172*82a0bb1aSRong Xu                                        ConstantInt::getTrue(Context),
173*82a0bb1aSRong Xu                                        FSDiscriminatorVar)});
174*82a0bb1aSRong Xu }
175*82a0bb1aSRong Xu 
1767397905aSRong Xu } // end of namespace sampleprofutil
1777397905aSRong Xu } // end of namespace llvm
178