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