1 //===- llvm/Analysis/ProfileSummaryInfo.h - profile summary ---*- C++ -*-===// 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 profile summary 10 // information. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_ANALYSIS_PROFILESUMMARYINFO_H 15 #define LLVM_ANALYSIS_PROFILESUMMARYINFO_H 16 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/IR/PassManager.h" 19 #include "llvm/IR/ProfileSummary.h" 20 #include "llvm/Pass.h" 21 #include <memory> 22 #include <optional> 23 24 namespace llvm { 25 class BasicBlock; 26 class BlockFrequencyInfo; 27 class CallBase; 28 class Function; 29 30 /// Analysis providing profile information. 31 /// 32 /// This is an immutable analysis pass that provides ability to query global 33 /// (program-level) profile information. The main APIs are isHotCount and 34 /// isColdCount that tells whether a given profile count is considered hot/cold 35 /// based on the profile summary. This also provides convenience methods to 36 /// check whether a function is hot or cold. 37 38 // FIXME: Provide convenience methods to determine hotness/coldness of other IR 39 // units. This would require making this depend on BFI. 40 class ProfileSummaryInfo { 41 private: 42 const Module *M; 43 std::unique_ptr<ProfileSummary> Summary; 44 void computeThresholds(); 45 // Count thresholds to answer isHotCount and isColdCount queries. 46 std::optional<uint64_t> HotCountThreshold, ColdCountThreshold; 47 // True if the working set size of the code is considered huge, 48 // because the number of profile counts required to reach the hot 49 // percentile is above a huge threshold. 50 std::optional<bool> HasHugeWorkingSetSize; 51 // True if the working set size of the code is considered large, 52 // because the number of profile counts required to reach the hot 53 // percentile is above a large threshold. 54 std::optional<bool> HasLargeWorkingSetSize; 55 // Compute the threshold for a given cutoff. 56 std::optional<uint64_t> computeThreshold(int PercentileCutoff) const; 57 // The map that caches the threshold values. The keys are the percentile 58 // cutoff values and the values are the corresponding threshold values. 59 mutable DenseMap<int, uint64_t> ThresholdCache; 60 61 public: 62 ProfileSummaryInfo(const Module &M) : M(&M) { refresh(); } 63 ProfileSummaryInfo(ProfileSummaryInfo &&Arg) = default; 64 65 /// If no summary is present, attempt to refresh. 66 void refresh(); 67 68 /// Returns true if profile summary is available. 69 bool hasProfileSummary() const { return Summary != nullptr; } 70 71 /// Returns true if module \c M has sample profile. 72 bool hasSampleProfile() const { 73 return hasProfileSummary() && 74 Summary->getKind() == ProfileSummary::PSK_Sample; 75 } 76 77 /// Returns true if module \c M has instrumentation profile. 78 bool hasInstrumentationProfile() const { 79 return hasProfileSummary() && 80 Summary->getKind() == ProfileSummary::PSK_Instr; 81 } 82 83 /// Returns true if module \c M has context sensitive instrumentation profile. 84 bool hasCSInstrumentationProfile() const { 85 return hasProfileSummary() && 86 Summary->getKind() == ProfileSummary::PSK_CSInstr; 87 } 88 89 /// Handle the invalidation of this information. 90 /// 91 /// When used as a result of \c ProfileSummaryAnalysis this method will be 92 /// called when the module this was computed for changes. Since profile 93 /// summary is immutable after it is annotated on the module, we return false 94 /// here. 95 bool invalidate(Module &, const PreservedAnalyses &, 96 ModuleAnalysisManager::Invalidator &) { 97 return false; 98 } 99 100 /// Returns the profile count for \p CallInst. 101 std::optional<uint64_t> getProfileCount(const CallBase &CallInst, 102 BlockFrequencyInfo *BFI, 103 bool AllowSynthetic = false) const; 104 /// Returns true if module \c M has partial-profile sample profile. 105 bool hasPartialSampleProfile() const; 106 /// Returns true if the working set size of the code is considered huge. 107 bool hasHugeWorkingSetSize() const; 108 /// Returns true if the working set size of the code is considered large. 109 bool hasLargeWorkingSetSize() const; 110 /// Returns true if \p F has hot function entry. 111 bool isFunctionEntryHot(const Function *F) const; 112 /// Returns true if \p F contains hot code. 113 bool isFunctionHotInCallGraph(const Function *F, 114 BlockFrequencyInfo &BFI) const; 115 /// Returns true if \p F has cold function entry. 116 bool isFunctionEntryCold(const Function *F) const; 117 /// Returns true if \p F contains only cold code. 118 bool isFunctionColdInCallGraph(const Function *F, 119 BlockFrequencyInfo &BFI) const; 120 /// Returns true if the hotness of \p F is unknown. 121 bool isFunctionHotnessUnknown(const Function &F) const; 122 /// Returns true if \p F contains hot code with regard to a given hot 123 /// percentile cutoff value. 124 bool isFunctionHotInCallGraphNthPercentile(int PercentileCutoff, 125 const Function *F, 126 BlockFrequencyInfo &BFI) const; 127 /// Returns true if \p F contains cold code with regard to a given cold 128 /// percentile cutoff value. 129 bool isFunctionColdInCallGraphNthPercentile(int PercentileCutoff, 130 const Function *F, 131 BlockFrequencyInfo &BFI) const; 132 /// Returns true if count \p C is considered hot. 133 bool isHotCount(uint64_t C) const; 134 /// Returns true if count \p C is considered cold. 135 bool isColdCount(uint64_t C) const; 136 /// Returns true if count \p C is considered hot with regard to a given 137 /// hot percentile cutoff value. 138 /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where 139 /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile. 140 bool isHotCountNthPercentile(int PercentileCutoff, uint64_t C) const; 141 /// Returns true if count \p C is considered cold with regard to a given 142 /// cold percentile cutoff value. 143 /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where 144 /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile. 145 bool isColdCountNthPercentile(int PercentileCutoff, uint64_t C) const; 146 /// Returns true if BasicBlock \p BB is considered hot. 147 bool isHotBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI) const; 148 /// Returns true if BasicBlock \p BB is considered cold. 149 bool isColdBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI) const; 150 /// Returns true if BasicBlock \p BB is considered hot with regard to a given 151 /// hot percentile cutoff value. 152 /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where 153 /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile. 154 bool isHotBlockNthPercentile(int PercentileCutoff, const BasicBlock *BB, 155 BlockFrequencyInfo *BFI) const; 156 /// Returns true if BasicBlock \p BB is considered cold with regard to a given 157 /// cold percentile cutoff value. 158 /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where 159 /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile. 160 bool isColdBlockNthPercentile(int PercentileCutoff, const BasicBlock *BB, 161 BlockFrequencyInfo *BFI) const; 162 /// Returns true if the call site \p CB is considered hot. 163 bool isHotCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const; 164 /// Returns true if call site \p CB is considered cold. 165 bool isColdCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const; 166 /// Returns HotCountThreshold if set. Recompute HotCountThreshold 167 /// if not set. 168 uint64_t getOrCompHotCountThreshold() const; 169 /// Returns ColdCountThreshold if set. Recompute HotCountThreshold 170 /// if not set. 171 uint64_t getOrCompColdCountThreshold() const; 172 /// Returns HotCountThreshold if set. 173 uint64_t getHotCountThreshold() const { 174 return HotCountThreshold.value_or(0); 175 } 176 /// Returns ColdCountThreshold if set. 177 uint64_t getColdCountThreshold() const { 178 return ColdCountThreshold.value_or(0); 179 } 180 181 private: 182 template <bool isHot> 183 bool isFunctionHotOrColdInCallGraphNthPercentile( 184 int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) const; 185 template <bool isHot> 186 bool isHotOrColdCountNthPercentile(int PercentileCutoff, uint64_t C) const; 187 template <bool isHot> 188 bool isHotOrColdBlockNthPercentile(int PercentileCutoff, 189 const BasicBlock *BB, 190 BlockFrequencyInfo *BFI) const; 191 }; 192 193 /// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo. 194 class ProfileSummaryInfoWrapperPass : public ImmutablePass { 195 std::unique_ptr<ProfileSummaryInfo> PSI; 196 197 public: 198 static char ID; 199 ProfileSummaryInfoWrapperPass(); 200 201 ProfileSummaryInfo &getPSI() { return *PSI; } 202 const ProfileSummaryInfo &getPSI() const { return *PSI; } 203 204 bool doInitialization(Module &M) override; 205 bool doFinalization(Module &M) override; 206 void getAnalysisUsage(AnalysisUsage &AU) const override { 207 AU.setPreservesAll(); 208 } 209 }; 210 211 /// An analysis pass based on the new PM to deliver ProfileSummaryInfo. 212 class ProfileSummaryAnalysis 213 : public AnalysisInfoMixin<ProfileSummaryAnalysis> { 214 public: 215 typedef ProfileSummaryInfo Result; 216 217 Result run(Module &M, ModuleAnalysisManager &); 218 219 private: 220 friend AnalysisInfoMixin<ProfileSummaryAnalysis>; 221 static AnalysisKey Key; 222 }; 223 224 /// Printer pass that uses \c ProfileSummaryAnalysis. 225 class ProfileSummaryPrinterPass 226 : public PassInfoMixin<ProfileSummaryPrinterPass> { 227 raw_ostream &OS; 228 229 public: 230 explicit ProfileSummaryPrinterPass(raw_ostream &OS) : OS(OS) {} 231 PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 232 }; 233 234 } // end namespace llvm 235 236 #endif 237