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