aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Analysis/ProfileSummaryInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/ProfileSummaryInfo.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Analysis/ProfileSummaryInfo.cpp263
1 files changed, 263 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Analysis/ProfileSummaryInfo.cpp b/contrib/llvm-project/llvm/lib/Analysis/ProfileSummaryInfo.cpp
new file mode 100644
index 000000000000..fdad14571dfe
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/Analysis/ProfileSummaryInfo.cpp
@@ -0,0 +1,263 @@
+//===- ProfileSummaryInfo.cpp - Global profile summary information --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass that provides access to the global profile summary
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/ProfileSummaryInfo.h"
+#include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/ProfileSummary.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/ProfileData/ProfileCommon.h"
+#include "llvm/Support/CommandLine.h"
+#include <optional>
+using namespace llvm;
+
+static cl::opt<bool> PartialProfile(
+ "partial-profile", cl::Hidden, cl::init(false),
+ cl::desc("Specify the current profile is used as a partial profile."));
+
+cl::opt<bool> ScalePartialSampleProfileWorkingSetSize(
+ "scale-partial-sample-profile-working-set-size", cl::Hidden, cl::init(true),
+ cl::desc(
+ "If true, scale the working set size of the partial sample profile "
+ "by the partial profile ratio to reflect the size of the program "
+ "being compiled."));
+
+static cl::opt<double> PartialSampleProfileWorkingSetSizeScaleFactor(
+ "partial-sample-profile-working-set-size-scale-factor", cl::Hidden,
+ cl::init(0.008),
+ cl::desc("The scale factor used to scale the working set size of the "
+ "partial sample profile along with the partial profile ratio. "
+ "This includes the factor of the profile counter per block "
+ "and the factor to scale the working set size to use the same "
+ "shared thresholds as PGO."));
+
+// The profile summary metadata may be attached either by the frontend or by
+// any backend passes (IR level instrumentation, for example). This method
+// checks if the Summary is null and if so checks if the summary metadata is now
+// available in the module and parses it to get the Summary object.
+void ProfileSummaryInfo::refresh() {
+ if (hasProfileSummary())
+ return;
+ // First try to get context sensitive ProfileSummary.
+ auto *SummaryMD = M->getProfileSummary(/* IsCS */ true);
+ if (SummaryMD)
+ Summary.reset(ProfileSummary::getFromMD(SummaryMD));
+
+ if (!hasProfileSummary()) {
+ // This will actually return PSK_Instr or PSK_Sample summary.
+ SummaryMD = M->getProfileSummary(/* IsCS */ false);
+ if (SummaryMD)
+ Summary.reset(ProfileSummary::getFromMD(SummaryMD));
+ }
+ if (!hasProfileSummary())
+ return;
+ computeThresholds();
+}
+
+std::optional<uint64_t> ProfileSummaryInfo::getProfileCount(
+ const CallBase &Call, BlockFrequencyInfo *BFI, bool AllowSynthetic) const {
+ assert((isa<CallInst>(Call) || isa<InvokeInst>(Call)) &&
+ "We can only get profile count for call/invoke instruction.");
+ if (hasSampleProfile()) {
+ // In sample PGO mode, check if there is a profile metadata on the
+ // instruction. If it is present, determine hotness solely based on that,
+ // since the sampled entry count may not be accurate. If there is no
+ // annotated on the instruction, return std::nullopt.
+ uint64_t TotalCount;
+ if (Call.extractProfTotalWeight(TotalCount))
+ return TotalCount;
+ return std::nullopt;
+ }
+ if (BFI)
+ return BFI->getBlockProfileCount(Call.getParent(), AllowSynthetic);
+ return std::nullopt;
+}
+
+bool ProfileSummaryInfo::isFunctionHotnessUnknown(const Function &F) const {
+ assert(hasPartialSampleProfile() && "Expect partial sample profile");
+ return !F.getEntryCount();
+}
+
+/// Returns true if the function's entry is a cold. If it returns false, it
+/// either means it is not cold or it is unknown whether it is cold or not (for
+/// example, no profile data is available).
+bool ProfileSummaryInfo::isFunctionEntryCold(const Function *F) const {
+ if (!F)
+ return false;
+ if (F->hasFnAttribute(Attribute::Cold))
+ return true;
+ if (!hasProfileSummary())
+ return false;
+ auto FunctionCount = F->getEntryCount();
+ // FIXME: The heuristic used below for determining coldness is based on
+ // preliminary SPEC tuning for inliner. This will eventually be a
+ // convenience method that calls isHotCount.
+ return FunctionCount && isColdCount(FunctionCount->getCount());
+}
+
+/// Compute the hot and cold thresholds.
+void ProfileSummaryInfo::computeThresholds() {
+ auto &DetailedSummary = Summary->getDetailedSummary();
+ auto &HotEntry = ProfileSummaryBuilder::getEntryForPercentile(
+ DetailedSummary, ProfileSummaryCutoffHot);
+ HotCountThreshold =
+ ProfileSummaryBuilder::getHotCountThreshold(DetailedSummary);
+ ColdCountThreshold =
+ ProfileSummaryBuilder::getColdCountThreshold(DetailedSummary);
+ assert(ColdCountThreshold <= HotCountThreshold &&
+ "Cold count threshold cannot exceed hot count threshold!");
+ if (!hasPartialSampleProfile() || !ScalePartialSampleProfileWorkingSetSize) {
+ HasHugeWorkingSetSize =
+ HotEntry.NumCounts > ProfileSummaryHugeWorkingSetSizeThreshold;
+ HasLargeWorkingSetSize =
+ HotEntry.NumCounts > ProfileSummaryLargeWorkingSetSizeThreshold;
+ } else {
+ // Scale the working set size of the partial sample profile to reflect the
+ // size of the program being compiled.
+ double PartialProfileRatio = Summary->getPartialProfileRatio();
+ uint64_t ScaledHotEntryNumCounts =
+ static_cast<uint64_t>(HotEntry.NumCounts * PartialProfileRatio *
+ PartialSampleProfileWorkingSetSizeScaleFactor);
+ HasHugeWorkingSetSize =
+ ScaledHotEntryNumCounts > ProfileSummaryHugeWorkingSetSizeThreshold;
+ HasLargeWorkingSetSize =
+ ScaledHotEntryNumCounts > ProfileSummaryLargeWorkingSetSizeThreshold;
+ }
+}
+
+std::optional<uint64_t>
+ProfileSummaryInfo::computeThreshold(int PercentileCutoff) const {
+ if (!hasProfileSummary())
+ return std::nullopt;
+ auto iter = ThresholdCache.find(PercentileCutoff);
+ if (iter != ThresholdCache.end()) {
+ return iter->second;
+ }
+ auto &DetailedSummary = Summary->getDetailedSummary();
+ auto &Entry = ProfileSummaryBuilder::getEntryForPercentile(DetailedSummary,
+ PercentileCutoff);
+ uint64_t CountThreshold = Entry.MinCount;
+ ThresholdCache[PercentileCutoff] = CountThreshold;
+ return CountThreshold;
+}
+
+bool ProfileSummaryInfo::hasHugeWorkingSetSize() const {
+ return HasHugeWorkingSetSize && *HasHugeWorkingSetSize;
+}
+
+bool ProfileSummaryInfo::hasLargeWorkingSetSize() const {
+ return HasLargeWorkingSetSize && *HasLargeWorkingSetSize;
+}
+
+bool ProfileSummaryInfo::isHotCount(uint64_t C) const {
+ return HotCountThreshold && C >= *HotCountThreshold;
+}
+
+bool ProfileSummaryInfo::isColdCount(uint64_t C) const {
+ return ColdCountThreshold && C <= *ColdCountThreshold;
+}
+
+template <bool isHot>
+bool ProfileSummaryInfo::isHotOrColdCountNthPercentile(int PercentileCutoff,
+ uint64_t C) const {
+ auto CountThreshold = computeThreshold(PercentileCutoff);
+ if (isHot)
+ return CountThreshold && C >= *CountThreshold;
+ else
+ return CountThreshold && C <= *CountThreshold;
+}
+
+bool ProfileSummaryInfo::isHotCountNthPercentile(int PercentileCutoff,
+ uint64_t C) const {
+ return isHotOrColdCountNthPercentile<true>(PercentileCutoff, C);
+}
+
+bool ProfileSummaryInfo::isColdCountNthPercentile(int PercentileCutoff,
+ uint64_t C) const {
+ return isHotOrColdCountNthPercentile<false>(PercentileCutoff, C);
+}
+
+uint64_t ProfileSummaryInfo::getOrCompHotCountThreshold() const {
+ return HotCountThreshold.value_or(UINT64_MAX);
+}
+
+uint64_t ProfileSummaryInfo::getOrCompColdCountThreshold() const {
+ return ColdCountThreshold.value_or(0);
+}
+
+bool ProfileSummaryInfo::isHotCallSite(const CallBase &CB,
+ BlockFrequencyInfo *BFI) const {
+ auto C = getProfileCount(CB, BFI);
+ return C && isHotCount(*C);
+}
+
+bool ProfileSummaryInfo::isColdCallSite(const CallBase &CB,
+ BlockFrequencyInfo *BFI) const {
+ auto C = getProfileCount(CB, BFI);
+ if (C)
+ return isColdCount(*C);
+
+ // In SamplePGO, if the caller has been sampled, and there is no profile
+ // annotated on the callsite, we consider the callsite as cold.
+ return hasSampleProfile() && CB.getCaller()->hasProfileData();
+}
+
+bool ProfileSummaryInfo::hasPartialSampleProfile() const {
+ return hasProfileSummary() &&
+ Summary->getKind() == ProfileSummary::PSK_Sample &&
+ (PartialProfile || Summary->isPartialProfile());
+}
+
+INITIALIZE_PASS(ProfileSummaryInfoWrapperPass, "profile-summary-info",
+ "Profile summary info", false, true)
+
+ProfileSummaryInfoWrapperPass::ProfileSummaryInfoWrapperPass()
+ : ImmutablePass(ID) {
+ initializeProfileSummaryInfoWrapperPassPass(*PassRegistry::getPassRegistry());
+}
+
+bool ProfileSummaryInfoWrapperPass::doInitialization(Module &M) {
+ PSI.reset(new ProfileSummaryInfo(M));
+ return false;
+}
+
+bool ProfileSummaryInfoWrapperPass::doFinalization(Module &M) {
+ PSI.reset();
+ return false;
+}
+
+AnalysisKey ProfileSummaryAnalysis::Key;
+ProfileSummaryInfo ProfileSummaryAnalysis::run(Module &M,
+ ModuleAnalysisManager &) {
+ return ProfileSummaryInfo(M);
+}
+
+PreservedAnalyses ProfileSummaryPrinterPass::run(Module &M,
+ ModuleAnalysisManager &AM) {
+ ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);
+
+ OS << "Functions in " << M.getName() << " with hot/cold annotations: \n";
+ for (auto &F : M) {
+ OS << F.getName();
+ if (PSI.isFunctionEntryHot(&F))
+ OS << " :hot entry ";
+ else if (PSI.isFunctionEntryCold(&F))
+ OS << " :cold entry ";
+ OS << "\n";
+ }
+ return PreservedAnalyses::all();
+}
+
+char ProfileSummaryInfoWrapperPass::ID = 0;