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   bool isHotCountNthPercentile(int PercentileCutoff, uint64_t C) const;
138   /// Returns true if count \p C is considered cold with regard to a given
139   /// cold percentile cutoff value.
140   bool isColdCountNthPercentile(int PercentileCutoff, uint64_t C) const;
141   /// Returns true if BasicBlock \p BB is considered hot.
142   bool isHotBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI) const;
143   /// Returns true if BasicBlock \p BB is considered cold.
144   bool isColdBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI) const;
145   /// Returns true if BasicBlock \p BB is considered hot with regard to a given
146   /// hot percentile cutoff value.
147   bool isHotBlockNthPercentile(int PercentileCutoff, const BasicBlock *BB,
148                                BlockFrequencyInfo *BFI) const;
149   /// Returns true if BasicBlock \p BB is considered cold with regard to a given
150   /// cold percentile cutoff value.
151   bool isColdBlockNthPercentile(int PercentileCutoff, const BasicBlock *BB,
152                                 BlockFrequencyInfo *BFI) const;
153   /// Returns true if the call site \p CB is considered hot.
154   bool isHotCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const;
155   /// Returns true if call site \p CB is considered cold.
156   bool isColdCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const;
157   /// Returns HotCountThreshold if set. Recompute HotCountThreshold
158   /// if not set.
159   uint64_t getOrCompHotCountThreshold() const;
160   /// Returns ColdCountThreshold if set. Recompute HotCountThreshold
161   /// if not set.
162   uint64_t getOrCompColdCountThreshold() const;
163   /// Returns HotCountThreshold if set.
164   uint64_t getHotCountThreshold() const {
165     return HotCountThreshold ? HotCountThreshold.getValue() : 0;
166   }
167   /// Returns ColdCountThreshold if set.
168   uint64_t getColdCountThreshold() const {
169     return ColdCountThreshold ? ColdCountThreshold.getValue() : 0;
170   }
171 
172  private:
173    template <bool isHot>
174    bool isFunctionHotOrColdInCallGraphNthPercentile(
175        int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) const;
176    template <bool isHot>
177    bool isHotOrColdCountNthPercentile(int PercentileCutoff, uint64_t C) const;
178    template <bool isHot>
179    bool isHotOrColdBlockNthPercentile(int PercentileCutoff,
180                                       const BasicBlock *BB,
181                                       BlockFrequencyInfo *BFI) const;
182 };
183 
184 /// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
185 class ProfileSummaryInfoWrapperPass : public ImmutablePass {
186   std::unique_ptr<ProfileSummaryInfo> PSI;
187 
188 public:
189   static char ID;
190   ProfileSummaryInfoWrapperPass();
191 
192   ProfileSummaryInfo &getPSI() { return *PSI; }
193   const ProfileSummaryInfo &getPSI() const { return *PSI; }
194 
195   bool doInitialization(Module &M) override;
196   bool doFinalization(Module &M) override;
197   void getAnalysisUsage(AnalysisUsage &AU) const override {
198     AU.setPreservesAll();
199   }
200 };
201 
202 /// An analysis pass based on the new PM to deliver ProfileSummaryInfo.
203 class ProfileSummaryAnalysis
204     : public AnalysisInfoMixin<ProfileSummaryAnalysis> {
205 public:
206   typedef ProfileSummaryInfo Result;
207 
208   Result run(Module &M, ModuleAnalysisManager &);
209 
210 private:
211   friend AnalysisInfoMixin<ProfileSummaryAnalysis>;
212   static AnalysisKey Key;
213 };
214 
215 /// Printer pass that uses \c ProfileSummaryAnalysis.
216 class ProfileSummaryPrinterPass
217     : public PassInfoMixin<ProfileSummaryPrinterPass> {
218   raw_ostream &OS;
219 
220 public:
221   explicit ProfileSummaryPrinterPass(raw_ostream &OS) : OS(OS) {}
222   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
223 };
224 
225 } // end namespace llvm
226 
227 #endif
228