xref: /freebsd/contrib/llvm-project/llvm/lib/Analysis/ProfileSummaryInfo.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- ProfileSummaryInfo.cpp - Global profile summary information --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a pass that provides access to the global profile summary
100b57cec5SDimitry Andric // information.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
150b57cec5SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h"
160b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
175ffd83dbSDimitry Andric #include "llvm/IR/Instructions.h"
180b57cec5SDimitry Andric #include "llvm/IR/Module.h"
190b57cec5SDimitry Andric #include "llvm/IR/ProfileSummary.h"
20480093f4SDimitry Andric #include "llvm/InitializePasses.h"
215ffd83dbSDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
22480093f4SDimitry Andric #include "llvm/Support/CommandLine.h"
23*bdd1243dSDimitry Andric #include <optional>
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric 
265ffd83dbSDimitry Andric static cl::opt<bool> PartialProfile(
275ffd83dbSDimitry Andric     "partial-profile", cl::Hidden, cl::init(false),
285ffd83dbSDimitry Andric     cl::desc("Specify the current profile is used as a partial profile."));
295ffd83dbSDimitry Andric 
305ffd83dbSDimitry Andric cl::opt<bool> ScalePartialSampleProfileWorkingSetSize(
315ffd83dbSDimitry Andric     "scale-partial-sample-profile-working-set-size", cl::Hidden, cl::init(true),
325ffd83dbSDimitry Andric     cl::desc(
335ffd83dbSDimitry Andric         "If true, scale the working set size of the partial sample profile "
345ffd83dbSDimitry Andric         "by the partial profile ratio to reflect the size of the program "
355ffd83dbSDimitry Andric         "being compiled."));
365ffd83dbSDimitry Andric 
375ffd83dbSDimitry Andric static cl::opt<double> PartialSampleProfileWorkingSetSizeScaleFactor(
385ffd83dbSDimitry Andric     "partial-sample-profile-working-set-size-scale-factor", cl::Hidden,
395ffd83dbSDimitry Andric     cl::init(0.008),
405ffd83dbSDimitry Andric     cl::desc("The scale factor used to scale the working set size of the "
415ffd83dbSDimitry Andric              "partial sample profile along with the partial profile ratio. "
425ffd83dbSDimitry Andric              "This includes the factor of the profile counter per block "
435ffd83dbSDimitry Andric              "and the factor to scale the working set size to use the same "
445ffd83dbSDimitry Andric              "shared thresholds as PGO."));
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric // The profile summary metadata may be attached either by the frontend or by
470b57cec5SDimitry Andric // any backend passes (IR level instrumentation, for example). This method
480b57cec5SDimitry Andric // checks if the Summary is null and if so checks if the summary metadata is now
495ffd83dbSDimitry Andric // available in the module and parses it to get the Summary object.
505ffd83dbSDimitry Andric void ProfileSummaryInfo::refresh() {
515ffd83dbSDimitry Andric   if (hasProfileSummary())
525ffd83dbSDimitry Andric     return;
530b57cec5SDimitry Andric   // First try to get context sensitive ProfileSummary.
54fe6060f1SDimitry Andric   auto *SummaryMD = M->getProfileSummary(/* IsCS */ true);
555ffd83dbSDimitry Andric   if (SummaryMD)
560b57cec5SDimitry Andric     Summary.reset(ProfileSummary::getFromMD(SummaryMD));
575ffd83dbSDimitry Andric 
585ffd83dbSDimitry Andric   if (!hasProfileSummary()) {
590b57cec5SDimitry Andric     // This will actually return PSK_Instr or PSK_Sample summary.
60fe6060f1SDimitry Andric     SummaryMD = M->getProfileSummary(/* IsCS */ false);
615ffd83dbSDimitry Andric     if (SummaryMD)
620b57cec5SDimitry Andric       Summary.reset(ProfileSummary::getFromMD(SummaryMD));
635ffd83dbSDimitry Andric   }
645ffd83dbSDimitry Andric   if (!hasProfileSummary())
655ffd83dbSDimitry Andric     return;
665ffd83dbSDimitry Andric   computeThresholds();
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
69*bdd1243dSDimitry Andric std::optional<uint64_t> ProfileSummaryInfo::getProfileCount(
705ffd83dbSDimitry Andric     const CallBase &Call, BlockFrequencyInfo *BFI, bool AllowSynthetic) const {
715ffd83dbSDimitry Andric   assert((isa<CallInst>(Call) || isa<InvokeInst>(Call)) &&
720b57cec5SDimitry Andric          "We can only get profile count for call/invoke instruction.");
730b57cec5SDimitry Andric   if (hasSampleProfile()) {
740b57cec5SDimitry Andric     // In sample PGO mode, check if there is a profile metadata on the
750b57cec5SDimitry Andric     // instruction. If it is present, determine hotness solely based on that,
760b57cec5SDimitry Andric     // since the sampled entry count may not be accurate. If there is no
77*bdd1243dSDimitry Andric     // annotated on the instruction, return std::nullopt.
780b57cec5SDimitry Andric     uint64_t TotalCount;
795ffd83dbSDimitry Andric     if (Call.extractProfTotalWeight(TotalCount))
800b57cec5SDimitry Andric       return TotalCount;
81*bdd1243dSDimitry Andric     return std::nullopt;
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   if (BFI)
845ffd83dbSDimitry Andric     return BFI->getBlockProfileCount(Call.getParent(), AllowSynthetic);
85*bdd1243dSDimitry Andric   return std::nullopt;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
885ffd83dbSDimitry Andric bool ProfileSummaryInfo::isFunctionHotnessUnknown(const Function &F) const {
895ffd83dbSDimitry Andric   assert(hasPartialSampleProfile() && "Expect partial sample profile");
9081ad6265SDimitry Andric   return !F.getEntryCount();
915ffd83dbSDimitry Andric }
928bcb0991SDimitry Andric 
930b57cec5SDimitry Andric /// Returns true if the function's entry is a cold. If it returns false, it
940b57cec5SDimitry Andric /// either means it is not cold or it is unknown whether it is cold or not (for
950b57cec5SDimitry Andric /// example, no profile data is available).
965ffd83dbSDimitry Andric bool ProfileSummaryInfo::isFunctionEntryCold(const Function *F) const {
970b57cec5SDimitry Andric   if (!F)
980b57cec5SDimitry Andric     return false;
990b57cec5SDimitry Andric   if (F->hasFnAttribute(Attribute::Cold))
1000b57cec5SDimitry Andric     return true;
1015ffd83dbSDimitry Andric   if (!hasProfileSummary())
1020b57cec5SDimitry Andric     return false;
1030b57cec5SDimitry Andric   auto FunctionCount = F->getEntryCount();
1040b57cec5SDimitry Andric   // FIXME: The heuristic used below for determining coldness is based on
1050b57cec5SDimitry Andric   // preliminary SPEC tuning for inliner. This will eventually be a
1060b57cec5SDimitry Andric   // convenience method that calls isHotCount.
107349cc55cSDimitry Andric   return FunctionCount && isColdCount(FunctionCount->getCount());
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric /// Compute the hot and cold thresholds.
1110b57cec5SDimitry Andric void ProfileSummaryInfo::computeThresholds() {
1120b57cec5SDimitry Andric   auto &DetailedSummary = Summary->getDetailedSummary();
1135ffd83dbSDimitry Andric   auto &HotEntry = ProfileSummaryBuilder::getEntryForPercentile(
1145ffd83dbSDimitry Andric       DetailedSummary, ProfileSummaryCutoffHot);
115fe6060f1SDimitry Andric   HotCountThreshold =
116fe6060f1SDimitry Andric       ProfileSummaryBuilder::getHotCountThreshold(DetailedSummary);
117fe6060f1SDimitry Andric   ColdCountThreshold =
118fe6060f1SDimitry Andric       ProfileSummaryBuilder::getColdCountThreshold(DetailedSummary);
1190b57cec5SDimitry Andric   assert(ColdCountThreshold <= HotCountThreshold &&
1200b57cec5SDimitry Andric          "Cold count threshold cannot exceed hot count threshold!");
1215ffd83dbSDimitry Andric   if (!hasPartialSampleProfile() || !ScalePartialSampleProfileWorkingSetSize) {
1220b57cec5SDimitry Andric     HasHugeWorkingSetSize =
1230b57cec5SDimitry Andric         HotEntry.NumCounts > ProfileSummaryHugeWorkingSetSizeThreshold;
1248bcb0991SDimitry Andric     HasLargeWorkingSetSize =
1258bcb0991SDimitry Andric         HotEntry.NumCounts > ProfileSummaryLargeWorkingSetSizeThreshold;
1265ffd83dbSDimitry Andric   } else {
1275ffd83dbSDimitry Andric     // Scale the working set size of the partial sample profile to reflect the
1285ffd83dbSDimitry Andric     // size of the program being compiled.
1295ffd83dbSDimitry Andric     double PartialProfileRatio = Summary->getPartialProfileRatio();
1305ffd83dbSDimitry Andric     uint64_t ScaledHotEntryNumCounts =
1315ffd83dbSDimitry Andric         static_cast<uint64_t>(HotEntry.NumCounts * PartialProfileRatio *
1325ffd83dbSDimitry Andric                               PartialSampleProfileWorkingSetSizeScaleFactor);
1335ffd83dbSDimitry Andric     HasHugeWorkingSetSize =
1345ffd83dbSDimitry Andric         ScaledHotEntryNumCounts > ProfileSummaryHugeWorkingSetSizeThreshold;
1355ffd83dbSDimitry Andric     HasLargeWorkingSetSize =
1365ffd83dbSDimitry Andric         ScaledHotEntryNumCounts > ProfileSummaryLargeWorkingSetSizeThreshold;
1375ffd83dbSDimitry Andric   }
1388bcb0991SDimitry Andric }
1398bcb0991SDimitry Andric 
140*bdd1243dSDimitry Andric std::optional<uint64_t>
1415ffd83dbSDimitry Andric ProfileSummaryInfo::computeThreshold(int PercentileCutoff) const {
1425ffd83dbSDimitry Andric   if (!hasProfileSummary())
143*bdd1243dSDimitry Andric     return std::nullopt;
1448bcb0991SDimitry Andric   auto iter = ThresholdCache.find(PercentileCutoff);
1458bcb0991SDimitry Andric   if (iter != ThresholdCache.end()) {
1468bcb0991SDimitry Andric     return iter->second;
1478bcb0991SDimitry Andric   }
1488bcb0991SDimitry Andric   auto &DetailedSummary = Summary->getDetailedSummary();
1495ffd83dbSDimitry Andric   auto &Entry = ProfileSummaryBuilder::getEntryForPercentile(DetailedSummary,
1505ffd83dbSDimitry Andric                                                              PercentileCutoff);
1518bcb0991SDimitry Andric   uint64_t CountThreshold = Entry.MinCount;
1528bcb0991SDimitry Andric   ThresholdCache[PercentileCutoff] = CountThreshold;
1538bcb0991SDimitry Andric   return CountThreshold;
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
1565ffd83dbSDimitry Andric bool ProfileSummaryInfo::hasHugeWorkingSetSize() const {
157*bdd1243dSDimitry Andric   return HasHugeWorkingSetSize && *HasHugeWorkingSetSize;
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1605ffd83dbSDimitry Andric bool ProfileSummaryInfo::hasLargeWorkingSetSize() const {
161*bdd1243dSDimitry Andric   return HasLargeWorkingSetSize && *HasLargeWorkingSetSize;
1628bcb0991SDimitry Andric }
1638bcb0991SDimitry Andric 
1645ffd83dbSDimitry Andric bool ProfileSummaryInfo::isHotCount(uint64_t C) const {
165*bdd1243dSDimitry Andric   return HotCountThreshold && C >= *HotCountThreshold;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1685ffd83dbSDimitry Andric bool ProfileSummaryInfo::isColdCount(uint64_t C) const {
169*bdd1243dSDimitry Andric   return ColdCountThreshold && C <= *ColdCountThreshold;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
1725ffd83dbSDimitry Andric template <bool isHot>
1735ffd83dbSDimitry Andric bool ProfileSummaryInfo::isHotOrColdCountNthPercentile(int PercentileCutoff,
1745ffd83dbSDimitry Andric                                                        uint64_t C) const {
1758bcb0991SDimitry Andric   auto CountThreshold = computeThreshold(PercentileCutoff);
1765ffd83dbSDimitry Andric   if (isHot)
177*bdd1243dSDimitry Andric     return CountThreshold && C >= *CountThreshold;
1785ffd83dbSDimitry Andric   else
179*bdd1243dSDimitry Andric     return CountThreshold && C <= *CountThreshold;
1808bcb0991SDimitry Andric }
1818bcb0991SDimitry Andric 
1825ffd83dbSDimitry Andric bool ProfileSummaryInfo::isHotCountNthPercentile(int PercentileCutoff,
1835ffd83dbSDimitry Andric                                                  uint64_t C) const {
1845ffd83dbSDimitry Andric   return isHotOrColdCountNthPercentile<true>(PercentileCutoff, C);
1855ffd83dbSDimitry Andric }
1865ffd83dbSDimitry Andric 
1875ffd83dbSDimitry Andric bool ProfileSummaryInfo::isColdCountNthPercentile(int PercentileCutoff,
1885ffd83dbSDimitry Andric                                                   uint64_t C) const {
1895ffd83dbSDimitry Andric   return isHotOrColdCountNthPercentile<false>(PercentileCutoff, C);
1905ffd83dbSDimitry Andric }
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric uint64_t ProfileSummaryInfo::getOrCompHotCountThreshold() const {
19381ad6265SDimitry Andric   return HotCountThreshold.value_or(UINT64_MAX);
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
1965ffd83dbSDimitry Andric uint64_t ProfileSummaryInfo::getOrCompColdCountThreshold() const {
19781ad6265SDimitry Andric   return ColdCountThreshold.value_or(0);
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
2005ffd83dbSDimitry Andric bool ProfileSummaryInfo::isHotCallSite(const CallBase &CB,
2015ffd83dbSDimitry Andric                                        BlockFrequencyInfo *BFI) const {
2025ffd83dbSDimitry Andric   auto C = getProfileCount(CB, BFI);
2030b57cec5SDimitry Andric   return C && isHotCount(*C);
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
2065ffd83dbSDimitry Andric bool ProfileSummaryInfo::isColdCallSite(const CallBase &CB,
2075ffd83dbSDimitry Andric                                         BlockFrequencyInfo *BFI) const {
2085ffd83dbSDimitry Andric   auto C = getProfileCount(CB, BFI);
2090b57cec5SDimitry Andric   if (C)
2100b57cec5SDimitry Andric     return isColdCount(*C);
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   // In SamplePGO, if the caller has been sampled, and there is no profile
2130b57cec5SDimitry Andric   // annotated on the callsite, we consider the callsite as cold.
2145ffd83dbSDimitry Andric   return hasSampleProfile() && CB.getCaller()->hasProfileData();
2155ffd83dbSDimitry Andric }
2165ffd83dbSDimitry Andric 
2175ffd83dbSDimitry Andric bool ProfileSummaryInfo::hasPartialSampleProfile() const {
2185ffd83dbSDimitry Andric   return hasProfileSummary() &&
2195ffd83dbSDimitry Andric          Summary->getKind() == ProfileSummary::PSK_Sample &&
2205ffd83dbSDimitry Andric          (PartialProfile || Summary->isPartialProfile());
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric INITIALIZE_PASS(ProfileSummaryInfoWrapperPass, "profile-summary-info",
2240b57cec5SDimitry Andric                 "Profile summary info", false, true)
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric ProfileSummaryInfoWrapperPass::ProfileSummaryInfoWrapperPass()
2270b57cec5SDimitry Andric     : ImmutablePass(ID) {
2280b57cec5SDimitry Andric   initializeProfileSummaryInfoWrapperPassPass(*PassRegistry::getPassRegistry());
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric bool ProfileSummaryInfoWrapperPass::doInitialization(Module &M) {
2320b57cec5SDimitry Andric   PSI.reset(new ProfileSummaryInfo(M));
2330b57cec5SDimitry Andric   return false;
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric bool ProfileSummaryInfoWrapperPass::doFinalization(Module &M) {
2370b57cec5SDimitry Andric   PSI.reset();
2380b57cec5SDimitry Andric   return false;
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric AnalysisKey ProfileSummaryAnalysis::Key;
2420b57cec5SDimitry Andric ProfileSummaryInfo ProfileSummaryAnalysis::run(Module &M,
2430b57cec5SDimitry Andric                                                ModuleAnalysisManager &) {
2440b57cec5SDimitry Andric   return ProfileSummaryInfo(M);
2450b57cec5SDimitry Andric }
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric PreservedAnalyses ProfileSummaryPrinterPass::run(Module &M,
2480b57cec5SDimitry Andric                                                  ModuleAnalysisManager &AM) {
2490b57cec5SDimitry Andric   ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   OS << "Functions in " << M.getName() << " with hot/cold annotations: \n";
2520b57cec5SDimitry Andric   for (auto &F : M) {
2530b57cec5SDimitry Andric     OS << F.getName();
2540b57cec5SDimitry Andric     if (PSI.isFunctionEntryHot(&F))
2550b57cec5SDimitry Andric       OS << " :hot entry ";
2560b57cec5SDimitry Andric     else if (PSI.isFunctionEntryCold(&F))
2570b57cec5SDimitry Andric       OS << " :cold entry ";
2580b57cec5SDimitry Andric     OS << "\n";
2590b57cec5SDimitry Andric   }
2600b57cec5SDimitry Andric   return PreservedAnalyses::all();
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric char ProfileSummaryInfoWrapperPass::ID = 0;
264