Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:16

0001 //===- llvm/Analysis/ProfileSummaryInfo.h - profile summary ---*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file contains a pass that provides access to profile summary
0010 // information.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_ANALYSIS_PROFILESUMMARYINFO_H
0015 #define LLVM_ANALYSIS_PROFILESUMMARYINFO_H
0016 
0017 #include "llvm/ADT/DenseMap.h"
0018 #include "llvm/IR/Function.h"
0019 #include "llvm/IR/Instructions.h"
0020 #include "llvm/IR/PassManager.h"
0021 #include "llvm/IR/ProfileSummary.h"
0022 #include "llvm/Pass.h"
0023 #include "llvm/Support/BlockFrequency.h"
0024 #include <memory>
0025 #include <optional>
0026 
0027 namespace llvm {
0028 class BlockFrequencyInfo;
0029 class MachineFunction;
0030 
0031 /// Analysis providing profile information.
0032 ///
0033 /// This is an immutable analysis pass that provides ability to query global
0034 /// (program-level) profile information. The main APIs are isHotCount and
0035 /// isColdCount that tells whether a given profile count is considered hot/cold
0036 /// based on the profile summary. This also provides convenience methods to
0037 /// check whether a function is hot or cold.
0038 
0039 // FIXME: Provide convenience methods to determine hotness/coldness of other IR
0040 // units. This would require making this depend on BFI.
0041 class ProfileSummaryInfo {
0042 private:
0043   const Module *M;
0044   std::unique_ptr<ProfileSummary> Summary;
0045   void computeThresholds();
0046   // Count thresholds to answer isHotCount and isColdCount queries.
0047   std::optional<uint64_t> HotCountThreshold, ColdCountThreshold;
0048   // True if the working set size of the code is considered huge,
0049   // because the number of profile counts required to reach the hot
0050   // percentile is above a huge threshold.
0051   std::optional<bool> HasHugeWorkingSetSize;
0052   // True if the working set size of the code is considered large,
0053   // because the number of profile counts required to reach the hot
0054   // percentile is above a large threshold.
0055   std::optional<bool> HasLargeWorkingSetSize;
0056   // Compute the threshold for a given cutoff.
0057   std::optional<uint64_t> computeThreshold(int PercentileCutoff) const;
0058   // The map that caches the threshold values. The keys are the percentile
0059   // cutoff values and the values are the corresponding threshold values.
0060   mutable DenseMap<int, uint64_t> ThresholdCache;
0061 
0062 public:
0063   ProfileSummaryInfo(const Module &M) : M(&M) { refresh(); }
0064   ProfileSummaryInfo(ProfileSummaryInfo &&Arg) = default;
0065 
0066   /// If no summary is present, attempt to refresh.
0067   void refresh();
0068 
0069   /// Returns true if profile summary is available.
0070   bool hasProfileSummary() const { return Summary != nullptr; }
0071 
0072   /// Returns true if module \c M has sample profile.
0073   bool hasSampleProfile() const {
0074     return hasProfileSummary() &&
0075            Summary->getKind() == ProfileSummary::PSK_Sample;
0076   }
0077 
0078   /// Returns true if module \c M has instrumentation profile.
0079   bool hasInstrumentationProfile() const {
0080     return hasProfileSummary() &&
0081            Summary->getKind() == ProfileSummary::PSK_Instr;
0082   }
0083 
0084   /// Returns true if module \c M has context sensitive instrumentation profile.
0085   bool hasCSInstrumentationProfile() const {
0086     return hasProfileSummary() &&
0087            Summary->getKind() == ProfileSummary::PSK_CSInstr;
0088   }
0089 
0090   /// Handle the invalidation of this information.
0091   ///
0092   /// When used as a result of \c ProfileSummaryAnalysis this method will be
0093   /// called when the module this was computed for changes. Since profile
0094   /// summary is immutable after it is annotated on the module, we return false
0095   /// here.
0096   bool invalidate(Module &, const PreservedAnalyses &,
0097                   ModuleAnalysisManager::Invalidator &) {
0098     return false;
0099   }
0100 
0101   /// Returns the profile count for \p CallInst.
0102   std::optional<uint64_t> getProfileCount(const CallBase &CallInst,
0103                                           BlockFrequencyInfo *BFI,
0104                                           bool AllowSynthetic = false) const;
0105   /// Returns true if module \c M has partial-profile sample profile.
0106   bool hasPartialSampleProfile() const;
0107   /// Returns true if the working set size of the code is considered huge.
0108   bool hasHugeWorkingSetSize() const;
0109   /// Returns true if the working set size of the code is considered large.
0110   bool hasLargeWorkingSetSize() const;
0111   /// Returns true if \p F has hot function entry. If it returns false, it
0112   /// either means it is not hot or it is unknown whether it is hot or not (for
0113   /// example, no profile data is available).
0114   template <typename FuncT> bool isFunctionEntryHot(const FuncT *F) const {
0115     if (!F || !hasProfileSummary())
0116       return false;
0117     std::optional<Function::ProfileCount> FunctionCount = getEntryCount(F);
0118     // FIXME: The heuristic used below for determining hotness is based on
0119     // preliminary SPEC tuning for inliner. This will eventually be a
0120     // convenience method that calls isHotCount.
0121     return FunctionCount && isHotCount(FunctionCount->getCount());
0122   }
0123 
0124   /// Returns true if \p F contains hot code.
0125   template <typename FuncT, typename BFIT>
0126   bool isFunctionHotInCallGraph(const FuncT *F, BFIT &BFI) const {
0127     if (!F || !hasProfileSummary())
0128       return false;
0129     if (auto FunctionCount = getEntryCount(F))
0130       if (isHotCount(FunctionCount->getCount()))
0131         return true;
0132 
0133     if (auto TotalCallCount = getTotalCallCount(F))
0134       if (isHotCount(*TotalCallCount))
0135         return true;
0136 
0137     for (const auto &BB : *F)
0138       if (isHotBlock(&BB, &BFI))
0139         return true;
0140     return false;
0141   }
0142   /// Returns true if \p F has cold function entry.
0143   bool isFunctionEntryCold(const Function *F) const;
0144   /// Returns true if \p F contains only cold code.
0145   template <typename FuncT, typename BFIT>
0146   bool isFunctionColdInCallGraph(const FuncT *F, BFIT &BFI) const {
0147     if (!F || !hasProfileSummary())
0148       return false;
0149     if (auto FunctionCount = getEntryCount(F))
0150       if (!isColdCount(FunctionCount->getCount()))
0151         return false;
0152 
0153     if (auto TotalCallCount = getTotalCallCount(F))
0154       if (!isColdCount(*TotalCallCount))
0155         return false;
0156 
0157     for (const auto &BB : *F)
0158       if (!isColdBlock(&BB, &BFI))
0159         return false;
0160     return true;
0161   }
0162   /// Returns true if the hotness of \p F is unknown.
0163   bool isFunctionHotnessUnknown(const Function &F) const;
0164   /// Returns true if \p F contains hot code with regard to a given hot
0165   /// percentile cutoff value.
0166   template <typename FuncT, typename BFIT>
0167   bool isFunctionHotInCallGraphNthPercentile(int PercentileCutoff,
0168                                              const FuncT *F, BFIT &BFI) const {
0169     return isFunctionHotOrColdInCallGraphNthPercentile<true, FuncT, BFIT>(
0170         PercentileCutoff, F, BFI);
0171   }
0172   /// Returns true if \p F contains cold code with regard to a given cold
0173   /// percentile cutoff value.
0174   template <typename FuncT, typename BFIT>
0175   bool isFunctionColdInCallGraphNthPercentile(int PercentileCutoff,
0176                                               const FuncT *F, BFIT &BFI) const {
0177     return isFunctionHotOrColdInCallGraphNthPercentile<false, FuncT, BFIT>(
0178         PercentileCutoff, F, BFI);
0179   }
0180   /// Returns true if count \p C is considered hot.
0181   bool isHotCount(uint64_t C) const;
0182   /// Returns true if count \p C is considered cold.
0183   bool isColdCount(uint64_t C) const;
0184   /// Returns true if count \p C is considered hot with regard to a given
0185   /// hot percentile cutoff value.
0186   /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where
0187   /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile.
0188   bool isHotCountNthPercentile(int PercentileCutoff, uint64_t C) const;
0189   /// Returns true if count \p C is considered cold with regard to a given
0190   /// cold percentile cutoff value.
0191   /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where
0192   /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile.
0193   bool isColdCountNthPercentile(int PercentileCutoff, uint64_t C) const;
0194 
0195   /// Returns true if BasicBlock \p BB is considered hot.
0196   template <typename BBType, typename BFIT>
0197   bool isHotBlock(const BBType *BB, BFIT *BFI) const {
0198     auto Count = BFI->getBlockProfileCount(BB);
0199     return Count && isHotCount(*Count);
0200   }
0201 
0202   /// Returns true if BasicBlock \p BB is considered cold.
0203   template <typename BBType, typename BFIT>
0204   bool isColdBlock(const BBType *BB, BFIT *BFI) const {
0205     auto Count = BFI->getBlockProfileCount(BB);
0206     return Count && isColdCount(*Count);
0207   }
0208 
0209   template <typename BFIT>
0210   bool isColdBlock(BlockFrequency BlockFreq, const BFIT *BFI) const {
0211     auto Count = BFI->getProfileCountFromFreq(BlockFreq);
0212     return Count && isColdCount(*Count);
0213   }
0214 
0215   template <typename BBType, typename BFIT>
0216   bool isHotBlockNthPercentile(int PercentileCutoff, const BBType *BB,
0217                                BFIT *BFI) const {
0218     return isHotOrColdBlockNthPercentile<true, BBType, BFIT>(PercentileCutoff,
0219                                                              BB, BFI);
0220   }
0221 
0222   template <typename BFIT>
0223   bool isHotBlockNthPercentile(int PercentileCutoff, BlockFrequency BlockFreq,
0224                                BFIT *BFI) const {
0225     return isHotOrColdBlockNthPercentile<true, BFIT>(PercentileCutoff,
0226                                                      BlockFreq, BFI);
0227   }
0228 
0229   /// Returns true if BasicBlock \p BB is considered cold with regard to a given
0230   /// cold percentile cutoff value.
0231   /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where
0232   /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile.
0233   template <typename BBType, typename BFIT>
0234   bool isColdBlockNthPercentile(int PercentileCutoff, const BBType *BB,
0235                                 BFIT *BFI) const {
0236     return isHotOrColdBlockNthPercentile<false, BBType, BFIT>(PercentileCutoff,
0237                                                               BB, BFI);
0238   }
0239   template <typename BFIT>
0240   bool isColdBlockNthPercentile(int PercentileCutoff, BlockFrequency BlockFreq,
0241                                 BFIT *BFI) const {
0242     return isHotOrColdBlockNthPercentile<false, BFIT>(PercentileCutoff,
0243                                                       BlockFreq, BFI);
0244   }
0245   /// Returns true if the call site \p CB is considered hot.
0246   bool isHotCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const;
0247   /// Returns true if call site \p CB is considered cold.
0248   bool isColdCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const;
0249   /// Returns HotCountThreshold if set. Recompute HotCountThreshold
0250   /// if not set.
0251   uint64_t getOrCompHotCountThreshold() const;
0252   /// Returns ColdCountThreshold if set. Recompute HotCountThreshold
0253   /// if not set.
0254   uint64_t getOrCompColdCountThreshold() const;
0255   /// Returns HotCountThreshold if set.
0256   uint64_t getHotCountThreshold() const {
0257     return HotCountThreshold.value_or(0);
0258   }
0259   /// Returns ColdCountThreshold if set.
0260   uint64_t getColdCountThreshold() const {
0261     return ColdCountThreshold.value_or(0);
0262   }
0263 
0264 private:
0265   template <typename FuncT>
0266   std::optional<uint64_t> getTotalCallCount(const FuncT *F) const {
0267     return std::nullopt;
0268   }
0269 
0270   template <bool isHot, typename FuncT, typename BFIT>
0271   bool isFunctionHotOrColdInCallGraphNthPercentile(int PercentileCutoff,
0272                                                    const FuncT *F,
0273                                                    BFIT &FI) const {
0274     if (!F || !hasProfileSummary())
0275       return false;
0276     if (auto FunctionCount = getEntryCount(F)) {
0277       if (isHot &&
0278           isHotCountNthPercentile(PercentileCutoff, FunctionCount->getCount()))
0279         return true;
0280       if (!isHot && !isColdCountNthPercentile(PercentileCutoff,
0281                                               FunctionCount->getCount()))
0282         return false;
0283     }
0284     if (auto TotalCallCount = getTotalCallCount(F)) {
0285       if (isHot && isHotCountNthPercentile(PercentileCutoff, *TotalCallCount))
0286         return true;
0287       if (!isHot &&
0288           !isColdCountNthPercentile(PercentileCutoff, *TotalCallCount))
0289         return false;
0290     }
0291     for (const auto &BB : *F) {
0292       if (isHot && isHotBlockNthPercentile(PercentileCutoff, &BB, &FI))
0293         return true;
0294       if (!isHot && !isColdBlockNthPercentile(PercentileCutoff, &BB, &FI))
0295         return false;
0296     }
0297     return !isHot;
0298   }
0299 
0300   template <bool isHot>
0301   bool isHotOrColdCountNthPercentile(int PercentileCutoff, uint64_t C) const;
0302 
0303   template <bool isHot, typename BBType, typename BFIT>
0304   bool isHotOrColdBlockNthPercentile(int PercentileCutoff, const BBType *BB,
0305                                      BFIT *BFI) const {
0306     auto Count = BFI->getBlockProfileCount(BB);
0307     if (isHot)
0308       return Count && isHotCountNthPercentile(PercentileCutoff, *Count);
0309     else
0310       return Count && isColdCountNthPercentile(PercentileCutoff, *Count);
0311   }
0312 
0313   template <bool isHot, typename BFIT>
0314   bool isHotOrColdBlockNthPercentile(int PercentileCutoff,
0315                                      BlockFrequency BlockFreq,
0316                                      BFIT *BFI) const {
0317     auto Count = BFI->getProfileCountFromFreq(BlockFreq);
0318     if (isHot)
0319       return Count && isHotCountNthPercentile(PercentileCutoff, *Count);
0320     else
0321       return Count && isColdCountNthPercentile(PercentileCutoff, *Count);
0322   }
0323 
0324   template <typename FuncT>
0325   std::optional<Function::ProfileCount> getEntryCount(const FuncT *F) const {
0326     return F->getEntryCount();
0327   }
0328 };
0329 
0330 template <>
0331 inline std::optional<uint64_t>
0332 ProfileSummaryInfo::getTotalCallCount<Function>(const Function *F) const {
0333   if (!hasSampleProfile())
0334     return std::nullopt;
0335   uint64_t TotalCallCount = 0;
0336   for (const auto &BB : *F)
0337     for (const auto &I : BB)
0338       if (isa<CallInst>(I) || isa<InvokeInst>(I))
0339         if (auto CallCount = getProfileCount(cast<CallBase>(I), nullptr))
0340           TotalCallCount += *CallCount;
0341   return TotalCallCount;
0342 }
0343 
0344 // Declare template specialization for llvm::MachineFunction. Do not implement
0345 // here, because we cannot include MachineFunction header here, that would break
0346 // dependency rules.
0347 template <>
0348 std::optional<Function::ProfileCount>
0349 ProfileSummaryInfo::getEntryCount<MachineFunction>(
0350     const MachineFunction *F) const;
0351 
0352 /// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
0353 class ProfileSummaryInfoWrapperPass : public ImmutablePass {
0354   std::unique_ptr<ProfileSummaryInfo> PSI;
0355 
0356 public:
0357   static char ID;
0358   ProfileSummaryInfoWrapperPass();
0359 
0360   ProfileSummaryInfo &getPSI() { return *PSI; }
0361   const ProfileSummaryInfo &getPSI() const { return *PSI; }
0362 
0363   bool doInitialization(Module &M) override;
0364   bool doFinalization(Module &M) override;
0365   void getAnalysisUsage(AnalysisUsage &AU) const override {
0366     AU.setPreservesAll();
0367   }
0368 };
0369 
0370 /// An analysis pass based on the new PM to deliver ProfileSummaryInfo.
0371 class ProfileSummaryAnalysis
0372     : public AnalysisInfoMixin<ProfileSummaryAnalysis> {
0373 public:
0374   typedef ProfileSummaryInfo Result;
0375 
0376   Result run(Module &M, ModuleAnalysisManager &);
0377 
0378 private:
0379   friend AnalysisInfoMixin<ProfileSummaryAnalysis>;
0380   static AnalysisKey Key;
0381 };
0382 
0383 /// Printer pass that uses \c ProfileSummaryAnalysis.
0384 class ProfileSummaryPrinterPass
0385     : public PassInfoMixin<ProfileSummaryPrinterPass> {
0386   raw_ostream &OS;
0387 
0388 public:
0389   explicit ProfileSummaryPrinterPass(raw_ostream &OS) : OS(OS) {}
0390   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
0391   static bool isRequired() { return true; }
0392 };
0393 
0394 } // end namespace llvm
0395 
0396 #endif