LLVM 20.0.0git
ProfileSummaryInfo.h
Go to the documentation of this file.
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/Function.h"
20#include "llvm/IR/PassManager.h"
22#include "llvm/Pass.h"
24#include <memory>
25#include <optional>
26
27namespace llvm {
28class BlockFrequencyInfo;
29class MachineFunction;
30
31/// Analysis providing profile information.
32///
33/// This is an immutable analysis pass that provides ability to query global
34/// (program-level) profile information. The main APIs are isHotCount and
35/// isColdCount that tells whether a given profile count is considered hot/cold
36/// based on the profile summary. This also provides convenience methods to
37/// check whether a function is hot or cold.
38
39// FIXME: Provide convenience methods to determine hotness/coldness of other IR
40// units. This would require making this depend on BFI.
42private:
43 const Module *M;
44 std::unique_ptr<ProfileSummary> Summary;
45 void computeThresholds();
46 // Count thresholds to answer isHotCount and isColdCount queries.
47 std::optional<uint64_t> HotCountThreshold, ColdCountThreshold;
48 // True if the working set size of the code is considered huge,
49 // because the number of profile counts required to reach the hot
50 // percentile is above a huge threshold.
51 std::optional<bool> HasHugeWorkingSetSize;
52 // True if the working set size of the code is considered large,
53 // because the number of profile counts required to reach the hot
54 // percentile is above a large threshold.
55 std::optional<bool> HasLargeWorkingSetSize;
56 // Compute the threshold for a given cutoff.
57 std::optional<uint64_t> computeThreshold(int PercentileCutoff) const;
58 // The map that caches the threshold values. The keys are the percentile
59 // cutoff values and the values are the corresponding threshold values.
60 mutable DenseMap<int, uint64_t> ThresholdCache;
61
62public:
63 ProfileSummaryInfo(const Module &M) : M(&M) { refresh(); }
65
66 /// If no summary is present, attempt to refresh.
67 void refresh();
68
69 /// Returns true if profile summary is available.
70 bool hasProfileSummary() const { return Summary != nullptr; }
71
72 /// Returns true if module \c M has sample profile.
73 bool hasSampleProfile() const {
74 return hasProfileSummary() &&
75 Summary->getKind() == ProfileSummary::PSK_Sample;
76 }
77
78 /// Returns true if module \c M has instrumentation profile.
80 return hasProfileSummary() &&
81 Summary->getKind() == ProfileSummary::PSK_Instr;
82 }
83
84 /// Returns true if module \c M has context sensitive instrumentation profile.
86 return hasProfileSummary() &&
87 Summary->getKind() == ProfileSummary::PSK_CSInstr;
88 }
89
90 /// Handle the invalidation of this information.
91 ///
92 /// When used as a result of \c ProfileSummaryAnalysis this method will be
93 /// called when the module this was computed for changes. Since profile
94 /// summary is immutable after it is annotated on the module, we return false
95 /// here.
98 return false;
99 }
100
101 /// Returns the profile count for \p CallInst.
102 std::optional<uint64_t> getProfileCount(const CallBase &CallInst,
104 bool AllowSynthetic = false) const;
105 /// Returns true if module \c M has partial-profile sample profile.
106 bool hasPartialSampleProfile() const;
107 /// Returns true if the working set size of the code is considered huge.
108 bool hasHugeWorkingSetSize() const;
109 /// Returns true if the working set size of the code is considered large.
110 bool hasLargeWorkingSetSize() const;
111 /// Returns true if \p F has hot function entry. If it returns false, it
112 /// either means it is not hot or it is unknown whether it is hot or not (for
113 /// example, no profile data is available).
114 template <typename FuncT> bool isFunctionEntryHot(const FuncT *F) const {
115 if (!F || !hasProfileSummary())
116 return false;
117 std::optional<Function::ProfileCount> FunctionCount = getEntryCount(F);
118 // FIXME: The heuristic used below for determining hotness is based on
119 // preliminary SPEC tuning for inliner. This will eventually be a
120 // convenience method that calls isHotCount.
121 return FunctionCount && isHotCount(FunctionCount->getCount());
122 }
123
124 /// Returns true if \p F contains hot code.
125 template <typename FuncT, typename BFIT>
126 bool isFunctionHotInCallGraph(const FuncT *F, BFIT &BFI) const {
127 if (!F || !hasProfileSummary())
128 return false;
129 if (auto FunctionCount = getEntryCount(F))
130 if (isHotCount(FunctionCount->getCount()))
131 return true;
132
133 if (auto TotalCallCount = getTotalCallCount(F))
134 if (isHotCount(*TotalCallCount))
135 return true;
136
137 for (const auto &BB : *F)
138 if (isHotBlock(&BB, &BFI))
139 return true;
140 return false;
141 }
142 /// Returns true if \p F has cold function entry.
143 bool isFunctionEntryCold(const Function *F) const;
144 /// Returns true if \p F contains only cold code.
145 template <typename FuncT, typename BFIT>
146 bool isFunctionColdInCallGraph(const FuncT *F, BFIT &BFI) const {
147 if (!F || !hasProfileSummary())
148 return false;
149 if (auto FunctionCount = getEntryCount(F))
150 if (!isColdCount(FunctionCount->getCount()))
151 return false;
152
153 if (auto TotalCallCount = getTotalCallCount(F))
154 if (!isColdCount(*TotalCallCount))
155 return false;
156
157 for (const auto &BB : *F)
158 if (!isColdBlock(&BB, &BFI))
159 return false;
160 return true;
161 }
162 /// Returns true if the hotness of \p F is unknown.
163 bool isFunctionHotnessUnknown(const Function &F) const;
164 /// Returns true if \p F contains hot code with regard to a given hot
165 /// percentile cutoff value.
166 template <typename FuncT, typename BFIT>
168 const FuncT *F, BFIT &BFI) const {
169 return isFunctionHotOrColdInCallGraphNthPercentile<true, FuncT, BFIT>(
170 PercentileCutoff, F, BFI);
171 }
172 /// Returns true if \p F contains cold code with regard to a given cold
173 /// percentile cutoff value.
174 template <typename FuncT, typename BFIT>
176 const FuncT *F, BFIT &BFI) const {
177 return isFunctionHotOrColdInCallGraphNthPercentile<false, FuncT, BFIT>(
178 PercentileCutoff, F, BFI);
179 }
180 /// Returns true if count \p C is considered hot.
181 bool isHotCount(uint64_t C) const;
182 /// Returns true if count \p C is considered cold.
183 bool isColdCount(uint64_t C) const;
184 /// Returns true if count \p C is considered hot with regard to a given
185 /// hot percentile cutoff value.
186 /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where
187 /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile.
189 /// Returns true if count \p C is considered cold with regard to a given
190 /// cold percentile cutoff value.
191 /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where
192 /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile.
194
195 /// Returns true if BasicBlock \p BB is considered hot.
196 template <typename BBType, typename BFIT>
197 bool isHotBlock(const BBType *BB, BFIT *BFI) const {
198 auto Count = BFI->getBlockProfileCount(BB);
199 return Count && isHotCount(*Count);
200 }
201
202 /// Returns true if BasicBlock \p BB is considered cold.
203 template <typename BBType, typename BFIT>
204 bool isColdBlock(const BBType *BB, BFIT *BFI) const {
205 auto Count = BFI->getBlockProfileCount(BB);
206 return Count && isColdCount(*Count);
207 }
208
209 template <typename BFIT>
210 bool isColdBlock(BlockFrequency BlockFreq, const BFIT *BFI) const {
211 auto Count = BFI->getProfileCountFromFreq(BlockFreq);
212 return Count && isColdCount(*Count);
213 }
214
215 template <typename BBType, typename BFIT>
216 bool isHotBlockNthPercentile(int PercentileCutoff, const BBType *BB,
217 BFIT *BFI) const {
218 return isHotOrColdBlockNthPercentile<true, BBType, BFIT>(PercentileCutoff,
219 BB, BFI);
220 }
221
222 template <typename BFIT>
224 BFIT *BFI) const {
225 return isHotOrColdBlockNthPercentile<true, BFIT>(PercentileCutoff,
226 BlockFreq, BFI);
227 }
228
229 /// Returns true if BasicBlock \p BB is considered cold with regard to a given
230 /// cold percentile cutoff value.
231 /// PercentileCutoff is encoded as a 6 digit decimal fixed point number, where
232 /// the first two digits are the whole part. E.g. 995000 for 99.5 percentile.
233 template <typename BBType, typename BFIT>
234 bool isColdBlockNthPercentile(int PercentileCutoff, const BBType *BB,
235 BFIT *BFI) const {
236 return isHotOrColdBlockNthPercentile<false, BBType, BFIT>(PercentileCutoff,
237 BB, BFI);
238 }
239 template <typename BFIT>
241 BFIT *BFI) const {
242 return isHotOrColdBlockNthPercentile<false, BFIT>(PercentileCutoff,
243 BlockFreq, BFI);
244 }
245 /// Returns true if the call site \p CB is considered hot.
246 bool isHotCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const;
247 /// Returns true if call site \p CB is considered cold.
248 bool isColdCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const;
249 /// Returns HotCountThreshold if set. Recompute HotCountThreshold
250 /// if not set.
252 /// Returns ColdCountThreshold if set. Recompute HotCountThreshold
253 /// if not set.
255 /// Returns HotCountThreshold if set.
257 return HotCountThreshold.value_or(0);
258 }
259 /// Returns ColdCountThreshold if set.
261 return ColdCountThreshold.value_or(0);
262 }
263
264private:
265 template <typename FuncT>
266 std::optional<uint64_t> getTotalCallCount(const FuncT *F) const {
267 return std::nullopt;
268 }
269
270 template <bool isHot, typename FuncT, typename BFIT>
271 bool isFunctionHotOrColdInCallGraphNthPercentile(int PercentileCutoff,
272 const FuncT *F,
273 BFIT &FI) const {
274 if (!F || !hasProfileSummary())
275 return false;
276 if (auto FunctionCount = getEntryCount(F)) {
277 if (isHot &&
278 isHotCountNthPercentile(PercentileCutoff, FunctionCount->getCount()))
279 return true;
281 FunctionCount->getCount()))
282 return false;
283 }
284 if (auto TotalCallCount = getTotalCallCount(F)) {
285 if (isHot && isHotCountNthPercentile(PercentileCutoff, *TotalCallCount))
286 return true;
287 if (!isHot &&
289 return false;
290 }
291 for (const auto &BB : *F) {
292 if (isHot && isHotBlockNthPercentile(PercentileCutoff, &BB, &FI))
293 return true;
294 if (!isHot && !isColdBlockNthPercentile(PercentileCutoff, &BB, &FI))
295 return false;
296 }
297 return !isHot;
298 }
299
300 template <bool isHot>
301 bool isHotOrColdCountNthPercentile(int PercentileCutoff, uint64_t C) const;
302
303 template <bool isHot, typename BBType, typename BFIT>
304 bool isHotOrColdBlockNthPercentile(int PercentileCutoff, const BBType *BB,
305 BFIT *BFI) const {
306 auto Count = BFI->getBlockProfileCount(BB);
307 if (isHot)
308 return Count && isHotCountNthPercentile(PercentileCutoff, *Count);
309 else
310 return Count && isColdCountNthPercentile(PercentileCutoff, *Count);
311 }
312
313 template <bool isHot, typename BFIT>
314 bool isHotOrColdBlockNthPercentile(int PercentileCutoff,
315 BlockFrequency BlockFreq,
316 BFIT *BFI) const {
317 auto Count = BFI->getProfileCountFromFreq(BlockFreq);
318 if (isHot)
319 return Count && isHotCountNthPercentile(PercentileCutoff, *Count);
320 else
321 return Count && isColdCountNthPercentile(PercentileCutoff, *Count);
322 }
323
324 template <typename FuncT>
325 std::optional<Function::ProfileCount> getEntryCount(const FuncT *F) const {
326 return F->getEntryCount();
327 }
328};
329
330template <>
331inline std::optional<uint64_t>
332ProfileSummaryInfo::getTotalCallCount<Function>(const Function *F) const {
333 if (!hasSampleProfile())
334 return std::nullopt;
335 uint64_t TotalCallCount = 0;
336 for (const auto &BB : *F)
337 for (const auto &I : BB)
338 if (isa<CallInst>(I) || isa<InvokeInst>(I))
339 if (auto CallCount = getProfileCount(cast<CallBase>(I), nullptr))
340 TotalCallCount += *CallCount;
341 return TotalCallCount;
342}
343
344// Declare template specialization for llvm::MachineFunction. Do not implement
345// here, because we cannot include MachineFunction header here, that would break
346// dependency rules.
347template <>
348std::optional<Function::ProfileCount>
349ProfileSummaryInfo::getEntryCount<MachineFunction>(
350 const MachineFunction *F) const;
351
352/// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
354 std::unique_ptr<ProfileSummaryInfo> PSI;
355
356public:
357 static char ID;
359
360 ProfileSummaryInfo &getPSI() { return *PSI; }
361 const ProfileSummaryInfo &getPSI() const { return *PSI; }
362
363 bool doInitialization(Module &M) override;
364 bool doFinalization(Module &M) override;
365 void getAnalysisUsage(AnalysisUsage &AU) const override {
366 AU.setPreservesAll();
367 }
368};
369
370/// An analysis pass based on the new PM to deliver ProfileSummaryInfo.
372 : public AnalysisInfoMixin<ProfileSummaryAnalysis> {
373public:
375
377
378private:
380 static AnalysisKey Key;
381};
382
383/// Printer pass that uses \c ProfileSummaryAnalysis.
385 : public PassInfoMixin<ProfileSummaryPrinterPass> {
386 raw_ostream &OS;
387
388public:
391 static bool isRequired() { return true; }
392};
393
394} // end namespace llvm
395
396#endif
This file defines the DenseMap class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
static cl::opt< unsigned > PercentileCutoff("mfs-psi-cutoff", cl::desc("Percentile profile summary cutoff used to " "determine cold blocks. Unused if set to zero."), cl::init(999950), cl::Hidden)
raw_pwrite_stream & OS
API to communicate dependencies between analyses during invalidation.
Definition: PassManager.h:292
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:253
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1120
This class represents a function call, abstracting a target machine's calling convention.
ImmutablePass class - This class is used to provide information that does not need to be run.
Definition: Pass.h:281
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:111
An analysis pass based on the new PM to deliver ProfileSummaryInfo.
Result run(Module &M, ModuleAnalysisManager &)
An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
bool doFinalization(Module &M) override
doFinalization - Virtual method overriden by subclasses to do any necessary clean up after all passes...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
bool doInitialization(Module &M) override
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
const ProfileSummaryInfo & getPSI() const
Analysis providing profile information.
bool hasCSInstrumentationProfile() const
Returns true if module M has context sensitive instrumentation profile.
uint64_t getOrCompColdCountThreshold() const
Returns ColdCountThreshold if set.
bool hasProfileSummary() const
Returns true if profile summary is available.
bool isHotBlockNthPercentile(int PercentileCutoff, const BBType *BB, BFIT *BFI) const
bool isFunctionColdInCallGraph(const FuncT *F, BFIT &BFI) const
Returns true if F contains only cold code.
bool isFunctionHotnessUnknown(const Function &F) const
Returns true if the hotness of F is unknown.
bool hasInstrumentationProfile() const
Returns true if module M has instrumentation profile.
void refresh()
If no summary is present, attempt to refresh.
std::optional< uint64_t > getProfileCount(const CallBase &CallInst, BlockFrequencyInfo *BFI, bool AllowSynthetic=false) const
Returns the profile count for CallInst.
bool isFunctionColdInCallGraphNthPercentile(int PercentileCutoff, const FuncT *F, BFIT &BFI) const
Returns true if F contains cold code with regard to a given cold percentile cutoff value.
bool hasSampleProfile() const
Returns true if module M has sample profile.
bool isFunctionEntryHot(const FuncT *F) const
Returns true if F has hot function entry.
bool isColdBlock(const BBType *BB, BFIT *BFI) const
Returns true if BasicBlock BB is considered cold.
bool isColdCount(uint64_t C) const
Returns true if count C is considered cold.
bool isFunctionHotInCallGraphNthPercentile(int PercentileCutoff, const FuncT *F, BFIT &BFI) const
Returns true if F contains hot code with regard to a given hot percentile cutoff value.
bool isColdCountNthPercentile(int PercentileCutoff, uint64_t C) const
Returns true if count C is considered cold with regard to a given cold percentile cutoff value.
bool isHotCountNthPercentile(int PercentileCutoff, uint64_t C) const
Returns true if count C is considered hot with regard to a given hot percentile cutoff value.
uint64_t getColdCountThreshold() const
Returns ColdCountThreshold if set.
bool isFunctionHotInCallGraph(const FuncT *F, BFIT &BFI) const
Returns true if F contains hot code.
bool isColdBlock(BlockFrequency BlockFreq, const BFIT *BFI) const
bool hasPartialSampleProfile() const
Returns true if module M has partial-profile sample profile.
bool hasLargeWorkingSetSize() const
Returns true if the working set size of the code is considered large.
bool isColdCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const
Returns true if call site CB is considered cold.
ProfileSummaryInfo(ProfileSummaryInfo &&Arg)=default
bool isHotCallSite(const CallBase &CB, BlockFrequencyInfo *BFI) const
Returns true if the call site CB is considered hot.
ProfileSummaryInfo(const Module &M)
uint64_t getHotCountThreshold() const
Returns HotCountThreshold if set.
bool isHotBlock(const BBType *BB, BFIT *BFI) const
Returns true if BasicBlock BB is considered hot.
bool isColdBlockNthPercentile(int PercentileCutoff, BlockFrequency BlockFreq, BFIT *BFI) const
bool isHotCount(uint64_t C) const
Returns true if count C is considered hot.
bool hasHugeWorkingSetSize() const
Returns true if the working set size of the code is considered huge.
bool isColdBlockNthPercentile(int PercentileCutoff, const BBType *BB, BFIT *BFI) const
Returns true if BasicBlock BB is considered cold with regard to a given cold percentile cutoff value.
uint64_t getOrCompHotCountThreshold() const
Returns HotCountThreshold if set.
bool isHotBlockNthPercentile(int PercentileCutoff, BlockFrequency BlockFreq, BFIT *BFI) const
bool invalidate(Module &, const PreservedAnalyses &, ModuleAnalysisManager::Invalidator &)
Handle the invalidation of this information.
bool isFunctionEntryCold(const Function *F) const
Returns true if F has cold function entry.
Printer pass that uses ProfileSummaryAnalysis.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
A CRTP mix-in that provides informational APIs needed for analysis passes.
Definition: PassManager.h:92
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition: Analysis.h:28
A CRTP mix-in to automatically provide informational APIs needed for passes.
Definition: PassManager.h:69