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