llvm-project
263 строки · 9.9 Кб
1//===- ProfileSummaryInfo.cpp - Global profile summary information --------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a pass that provides access to the global profile summary
10// information.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Analysis/ProfileSummaryInfo.h"15#include "llvm/Analysis/BlockFrequencyInfo.h"16#include "llvm/IR/BasicBlock.h"17#include "llvm/IR/Instructions.h"18#include "llvm/IR/Module.h"19#include "llvm/IR/ProfileSummary.h"20#include "llvm/InitializePasses.h"21#include "llvm/ProfileData/ProfileCommon.h"22#include "llvm/Support/CommandLine.h"23#include <optional>24using namespace llvm;25
26static cl::opt<bool> PartialProfile(27"partial-profile", cl::Hidden, cl::init(false),28cl::desc("Specify the current profile is used as a partial profile."));29
30cl::opt<bool> ScalePartialSampleProfileWorkingSetSize(31"scale-partial-sample-profile-working-set-size", cl::Hidden, cl::init(true),32cl::desc(33"If true, scale the working set size of the partial sample profile "34"by the partial profile ratio to reflect the size of the program "35"being compiled."));36
37static cl::opt<double> PartialSampleProfileWorkingSetSizeScaleFactor(38"partial-sample-profile-working-set-size-scale-factor", cl::Hidden,39cl::init(0.008),40cl::desc("The scale factor used to scale the working set size of the "41"partial sample profile along with the partial profile ratio. "42"This includes the factor of the profile counter per block "43"and the factor to scale the working set size to use the same "44"shared thresholds as PGO."));45
46// The profile summary metadata may be attached either by the frontend or by
47// any backend passes (IR level instrumentation, for example). This method
48// checks if the Summary is null and if so checks if the summary metadata is now
49// available in the module and parses it to get the Summary object.
50void ProfileSummaryInfo::refresh() {51if (hasProfileSummary())52return;53// First try to get context sensitive ProfileSummary.54auto *SummaryMD = M->getProfileSummary(/* IsCS */ true);55if (SummaryMD)56Summary.reset(ProfileSummary::getFromMD(SummaryMD));57
58if (!hasProfileSummary()) {59// This will actually return PSK_Instr or PSK_Sample summary.60SummaryMD = M->getProfileSummary(/* IsCS */ false);61if (SummaryMD)62Summary.reset(ProfileSummary::getFromMD(SummaryMD));63}64if (!hasProfileSummary())65return;66computeThresholds();67}
68
69std::optional<uint64_t> ProfileSummaryInfo::getProfileCount(70const CallBase &Call, BlockFrequencyInfo *BFI, bool AllowSynthetic) const {71assert((isa<CallInst>(Call) || isa<InvokeInst>(Call)) &&72"We can only get profile count for call/invoke instruction.");73if (hasSampleProfile()) {74// In sample PGO mode, check if there is a profile metadata on the75// instruction. If it is present, determine hotness solely based on that,76// since the sampled entry count may not be accurate. If there is no77// annotated on the instruction, return std::nullopt.78uint64_t TotalCount;79if (Call.extractProfTotalWeight(TotalCount))80return TotalCount;81return std::nullopt;82}83if (BFI)84return BFI->getBlockProfileCount(Call.getParent(), AllowSynthetic);85return std::nullopt;86}
87
88bool ProfileSummaryInfo::isFunctionHotnessUnknown(const Function &F) const {89assert(hasPartialSampleProfile() && "Expect partial sample profile");90return !F.getEntryCount();91}
92
93/// Returns true if the function's entry is a cold. If it returns false, it
94/// either means it is not cold or it is unknown whether it is cold or not (for
95/// example, no profile data is available).
96bool ProfileSummaryInfo::isFunctionEntryCold(const Function *F) const {97if (!F)98return false;99if (F->hasFnAttribute(Attribute::Cold))100return true;101if (!hasProfileSummary())102return false;103auto FunctionCount = F->getEntryCount();104// FIXME: The heuristic used below for determining coldness is based on105// preliminary SPEC tuning for inliner. This will eventually be a106// convenience method that calls isHotCount.107return FunctionCount && isColdCount(FunctionCount->getCount());108}
109
110/// Compute the hot and cold thresholds.
111void ProfileSummaryInfo::computeThresholds() {112auto &DetailedSummary = Summary->getDetailedSummary();113auto &HotEntry = ProfileSummaryBuilder::getEntryForPercentile(114DetailedSummary, ProfileSummaryCutoffHot);115HotCountThreshold =116ProfileSummaryBuilder::getHotCountThreshold(DetailedSummary);117ColdCountThreshold =118ProfileSummaryBuilder::getColdCountThreshold(DetailedSummary);119assert(ColdCountThreshold <= HotCountThreshold &&120"Cold count threshold cannot exceed hot count threshold!");121if (!hasPartialSampleProfile() || !ScalePartialSampleProfileWorkingSetSize) {122HasHugeWorkingSetSize =123HotEntry.NumCounts > ProfileSummaryHugeWorkingSetSizeThreshold;124HasLargeWorkingSetSize =125HotEntry.NumCounts > ProfileSummaryLargeWorkingSetSizeThreshold;126} else {127// Scale the working set size of the partial sample profile to reflect the128// size of the program being compiled.129double PartialProfileRatio = Summary->getPartialProfileRatio();130uint64_t ScaledHotEntryNumCounts =131static_cast<uint64_t>(HotEntry.NumCounts * PartialProfileRatio *132PartialSampleProfileWorkingSetSizeScaleFactor);133HasHugeWorkingSetSize =134ScaledHotEntryNumCounts > ProfileSummaryHugeWorkingSetSizeThreshold;135HasLargeWorkingSetSize =136ScaledHotEntryNumCounts > ProfileSummaryLargeWorkingSetSizeThreshold;137}138}
139
140std::optional<uint64_t>141ProfileSummaryInfo::computeThreshold(int PercentileCutoff) const {142if (!hasProfileSummary())143return std::nullopt;144auto iter = ThresholdCache.find(PercentileCutoff);145if (iter != ThresholdCache.end()) {146return iter->second;147}148auto &DetailedSummary = Summary->getDetailedSummary();149auto &Entry = ProfileSummaryBuilder::getEntryForPercentile(DetailedSummary,150PercentileCutoff);151uint64_t CountThreshold = Entry.MinCount;152ThresholdCache[PercentileCutoff] = CountThreshold;153return CountThreshold;154}
155
156bool ProfileSummaryInfo::hasHugeWorkingSetSize() const {157return HasHugeWorkingSetSize && *HasHugeWorkingSetSize;158}
159
160bool ProfileSummaryInfo::hasLargeWorkingSetSize() const {161return HasLargeWorkingSetSize && *HasLargeWorkingSetSize;162}
163
164bool ProfileSummaryInfo::isHotCount(uint64_t C) const {165return HotCountThreshold && C >= *HotCountThreshold;166}
167
168bool ProfileSummaryInfo::isColdCount(uint64_t C) const {169return ColdCountThreshold && C <= *ColdCountThreshold;170}
171
172template <bool isHot>173bool ProfileSummaryInfo::isHotOrColdCountNthPercentile(int PercentileCutoff,174uint64_t C) const {175auto CountThreshold = computeThreshold(PercentileCutoff);176if (isHot)177return CountThreshold && C >= *CountThreshold;178else179return CountThreshold && C <= *CountThreshold;180}
181
182bool ProfileSummaryInfo::isHotCountNthPercentile(int PercentileCutoff,183uint64_t C) const {184return isHotOrColdCountNthPercentile<true>(PercentileCutoff, C);185}
186
187bool ProfileSummaryInfo::isColdCountNthPercentile(int PercentileCutoff,188uint64_t C) const {189return isHotOrColdCountNthPercentile<false>(PercentileCutoff, C);190}
191
192uint64_t ProfileSummaryInfo::getOrCompHotCountThreshold() const {193return HotCountThreshold.value_or(UINT64_MAX);194}
195
196uint64_t ProfileSummaryInfo::getOrCompColdCountThreshold() const {197return ColdCountThreshold.value_or(0);198}
199
200bool ProfileSummaryInfo::isHotCallSite(const CallBase &CB,201BlockFrequencyInfo *BFI) const {202auto C = getProfileCount(CB, BFI);203return C && isHotCount(*C);204}
205
206bool ProfileSummaryInfo::isColdCallSite(const CallBase &CB,207BlockFrequencyInfo *BFI) const {208auto C = getProfileCount(CB, BFI);209if (C)210return isColdCount(*C);211
212// In SamplePGO, if the caller has been sampled, and there is no profile213// annotated on the callsite, we consider the callsite as cold.214return hasSampleProfile() && CB.getCaller()->hasProfileData();215}
216
217bool ProfileSummaryInfo::hasPartialSampleProfile() const {218return hasProfileSummary() &&219Summary->getKind() == ProfileSummary::PSK_Sample &&220(PartialProfile || Summary->isPartialProfile());221}
222
223INITIALIZE_PASS(ProfileSummaryInfoWrapperPass, "profile-summary-info",224"Profile summary info", false, true)225
226ProfileSummaryInfoWrapperPass::ProfileSummaryInfoWrapperPass()227: ImmutablePass(ID) {228initializeProfileSummaryInfoWrapperPassPass(*PassRegistry::getPassRegistry());229}
230
231bool ProfileSummaryInfoWrapperPass::doInitialization(Module &M) {232PSI.reset(new ProfileSummaryInfo(M));233return false;234}
235
236bool ProfileSummaryInfoWrapperPass::doFinalization(Module &M) {237PSI.reset();238return false;239}
240
241AnalysisKey ProfileSummaryAnalysis::Key;242ProfileSummaryInfo ProfileSummaryAnalysis::run(Module &M,243ModuleAnalysisManager &) {244return ProfileSummaryInfo(M);245}
246
247PreservedAnalyses ProfileSummaryPrinterPass::run(Module &M,248ModuleAnalysisManager &AM) {249ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);250
251OS << "Functions in " << M.getName() << " with hot/cold annotations: \n";252for (auto &F : M) {253OS << F.getName();254if (PSI.isFunctionEntryHot(&F))255OS << " :hot entry ";256else if (PSI.isFunctionEntryCold(&F))257OS << " :cold entry ";258OS << "\n";259}260return PreservedAnalyses::all();261}
262
263char ProfileSummaryInfoWrapperPass::ID = 0;264