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