LLVM 24.0.0git
SampleProfileInference.h
Go to the documentation of this file.
1//===- Transforms/Utils/SampleProfileInference.h ----------*- 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/// \file
10/// This file provides the interface for the profile inference algorithm, profi.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
15#define LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
16
17#include "llvm/ADT/DenseMap.h"
20#include <vector>
21
22namespace llvm {
23
24struct FlowJump;
25
26/// A wrapper of a binary basic block.
27struct FlowBlock {
30 bool HasUnknownWeight{true};
31 bool IsUnlikely{false};
33 std::vector<FlowJump *> SuccJumps;
34 std::vector<FlowJump *> PredJumps;
35
36 /// Check if it is the entry block in the function.
37 bool isEntry() const { return PredJumps.empty(); }
38
39 /// Check if it is an exit block in the function.
40 bool isExit() const { return SuccJumps.empty(); }
41};
42
43/// A wrapper of a jump between two basic blocks.
52
53/// A wrapper of binary function with basic blocks and jumps.
55 /// Basic blocks in the function.
56 std::vector<FlowBlock> Blocks;
57 /// Jumps between the basic blocks.
58 std::vector<FlowJump> Jumps;
59 /// The index of the entry block.
61};
62
63/// Various thresholds and options controlling the behavior of the profile
64/// inference algorithm. Default values are tuned for several large-scale
65/// applications, and can be modified via corresponding command-line flags.
67 /// Evenly distribute flow when there are multiple equally likely options.
69
70 /// Evenly re-distribute flow among unknown subgraphs.
71 bool RebalanceUnknown{false};
72
73 /// Join isolated components having positive flow.
74 bool JoinIslands{false};
75
76 /// The cost of increasing a block's count by one.
77 unsigned CostBlockInc{0};
78
79 /// The cost of decreasing a block's count by one.
80 unsigned CostBlockDec{0};
81
82 /// The cost of increasing a count of zero-weight block by one.
83 unsigned CostBlockZeroInc{0};
84
85 /// The cost of increasing the entry block's count by one.
86 unsigned CostBlockEntryInc{0};
87
88 /// The cost of decreasing the entry block's count by one.
89 unsigned CostBlockEntryDec{0};
90
91 /// The cost of increasing an unknown block's count by one.
93
94 /// The cost of increasing a jump's count by one.
95 unsigned CostJumpInc{0};
96
97 /// The cost of increasing a fall-through jump's count by one.
98 unsigned CostJumpFTInc{0};
99
100 /// The cost of decreasing a jump's count by one.
101 unsigned CostJumpDec{0};
102
103 /// The cost of decreasing a fall-through jump's count by one.
104 unsigned CostJumpFTDec{0};
105
106 /// The cost of increasing an unknown jump's count by one.
108
109 /// The cost of increasing an unknown fall-through jump's count by one.
111
112 /// The cost of taking an unlikely block/jump.
113 const int64_t CostUnlikely = ((int64_t)1) << 30;
114};
115
116LLVM_ABI void applyFlowInference(const ProfiParams &Params, FlowFunction &Func);
118
119/// Sample profile inference pass.
120template <typename FT> class SampleProfileInference {
121public:
123 using BasicBlockT = std::remove_pointer_t<NodeRef>;
124 using FunctionT = FT;
125 using Edge = std::pair<const BasicBlockT *, const BasicBlockT *>;
130
132 BlockWeightMap &SampleBlockWeights)
133 : F(F), Successors(Successors), SampleBlockWeights(SampleBlockWeights) {}
135 BlockWeightMap &SampleBlockWeights,
136 EdgeWeightMap &SampleEdgeWeights)
137 : F(F), Successors(Successors), SampleBlockWeights(SampleBlockWeights),
138 SampleEdgeWeights(SampleEdgeWeights) {}
139
140 /// Apply the profile inference algorithm for a given function
141 void apply(BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights);
142
143private:
144 /// Initialize flow function blocks, jumps and misc metadata.
146 createFlowFunction(const std::vector<const BasicBlockT *> &BasicBlocks,
148
149 /// Try to infer branch probabilities mimicking implementation of
150 /// BranchProbabilityInfo. Unlikely taken branches are marked so that the
151 /// inference algorithm can avoid sending flow along corresponding edges.
152 void findUnlikelyJumps(const std::vector<const BasicBlockT *> &BasicBlocks,
153 BlockEdgeMap &Successors, FlowFunction &Func);
154
155 /// Determine whether the block is an exit in the CFG.
156 bool isExit(const BasicBlockT *BB);
157
158 /// Function.
159 const FunctionT &F;
160
161 /// Successors for each basic block in the CFG.
162 BlockEdgeMap &Successors;
163
164 /// Map basic blocks to their sampled weights.
165 BlockWeightMap &SampleBlockWeights;
166
167 /// Map edges to their sampled weights.
168 EdgeWeightMap SampleEdgeWeights;
169};
170
171template <typename BT>
173 EdgeWeightMap &EdgeWeights) {
174 // Find all forwards reachable blocks which the inference algorithm will be
175 // applied on.
177 for (auto *BB : depth_first_ext(&F, Reachable))
178 (void)BB /* Mark all reachable blocks */;
179
180 // Find all backwards reachable blocks which the inference algorithm will be
181 // applied on.
183 for (const auto &BB : F) {
184 // An exit block is a block without any successors.
185 if (isExit(&BB)) {
186 for (auto *RBB : inverse_depth_first_ext(&BB, InverseReachable))
187 (void)RBB;
188 }
189 }
190
191 // Keep a stable order for reachable blocks
193 std::vector<const BasicBlockT *> BasicBlocks;
194 BlockIndex.reserve(Reachable.size());
195 BasicBlocks.reserve(Reachable.size());
196 for (const auto &BB : F) {
197 if (Reachable.count(&BB) && InverseReachable.count(&BB)) {
198 BlockIndex[&BB] = BasicBlocks.size();
199 BasicBlocks.push_back(&BB);
200 }
201 }
202
203 BlockWeights.clear();
204 EdgeWeights.clear();
205 bool HasSamples = false;
206 for (const auto *BB : BasicBlocks) {
207 auto It = SampleBlockWeights.find(BB);
208 if (It != SampleBlockWeights.end() && It->second > 0) {
209 HasSamples = true;
210 BlockWeights[BB] = It->second;
211 }
212 }
213 // Quit early for functions with a single block or ones w/o samples
214 if (BasicBlocks.size() <= 1 || !HasSamples) {
215 return;
216 }
217
218 // Create necessary objects
219 FlowFunction Func = createFlowFunction(BasicBlocks, BlockIndex);
220
221 // Create and apply the inference network model.
222 applyFlowInference(Func);
223
224 // Extract the resulting weights from the control flow
225 // All weights are increased by one to avoid propagation errors introduced by
226 // zero weights.
227 for (const auto *BB : BasicBlocks) {
228 BlockWeights[BB] = Func.Blocks[BlockIndex[BB]].Flow;
229 }
230 for (auto &Jump : Func.Jumps) {
231 Edge E = std::make_pair(BasicBlocks[Jump.Source], BasicBlocks[Jump.Target]);
232 EdgeWeights[E] = Jump.Flow;
233 }
234
235#ifndef NDEBUG
236 // Unreachable blocks and edges should not have a weight.
237 for (auto &I : BlockWeights) {
238 assert(Reachable.contains(I.first));
239 assert(InverseReachable.contains(I.first));
240 }
241 for (auto &I : EdgeWeights) {
242 assert(Reachable.contains(I.first.first) &&
243 Reachable.contains(I.first.second));
244 assert(InverseReachable.contains(I.first.first) &&
245 InverseReachable.contains(I.first.second));
246 }
247#endif
248}
249
250template <typename BT>
251FlowFunction SampleProfileInference<BT>::createFlowFunction(
252 const std::vector<const BasicBlockT *> &BasicBlocks,
254 FlowFunction Func;
255 Func.Blocks.reserve(BasicBlocks.size());
256 // Create FlowBlocks
257 for (const auto *BB : BasicBlocks) {
259 auto It = SampleBlockWeights.find(BB);
260 if (It != SampleBlockWeights.end()) {
261 Block.HasUnknownWeight = false;
262 Block.Weight = It->second;
263 } else {
264 Block.HasUnknownWeight = true;
265 Block.Weight = 0;
266 }
267 Block.Index = Func.Blocks.size();
268 Func.Blocks.push_back(Block);
269 }
270 // Create FlowEdges
271 for (const auto *BB : BasicBlocks) {
272 for (auto *Succ : Successors[BB]) {
273 if (!BlockIndex.count(Succ))
274 continue;
275 FlowJump Jump;
276 Jump.Source = BlockIndex[BB];
277 Jump.Target = BlockIndex[Succ];
278 auto It = SampleEdgeWeights.find(std::make_pair(BB, Succ));
279 if (It != SampleEdgeWeights.end()) {
280 Jump.HasUnknownWeight = false;
281 Jump.Weight = It->second;
282 } else {
283 Jump.HasUnknownWeight = true;
284 Jump.Weight = 0;
285 }
286 Func.Jumps.push_back(Jump);
287 }
288 }
289 for (auto &Jump : Func.Jumps) {
290 uint64_t Src = Jump.Source;
291 uint64_t Dst = Jump.Target;
292 Func.Blocks[Src].SuccJumps.push_back(&Jump);
293 Func.Blocks[Dst].PredJumps.push_back(&Jump);
294 }
295
296 // Try to infer probabilities of jumps based on the content of basic block
297 findUnlikelyJumps(BasicBlocks, Successors, Func);
298
299 // Find the entry block
300 for (size_t I = 0; I < Func.Blocks.size(); I++) {
301 if (Func.Blocks[I].isEntry()) {
302 Func.Entry = I;
303 break;
304 }
305 }
306 assert(Func.Entry == 0 && "incorrect index of the entry block");
307
308 // Pre-process data: make sure the entry weight is at least 1
309 auto &EntryBlock = Func.Blocks[Func.Entry];
310 if (EntryBlock.Weight == 0 && !EntryBlock.HasUnknownWeight) {
311 EntryBlock.Weight = 1;
312 EntryBlock.HasUnknownWeight = false;
313 }
314
315 return Func;
316}
317
318template <typename BT>
319inline void SampleProfileInference<BT>::findUnlikelyJumps(
320 const std::vector<const BasicBlockT *> &BasicBlocks,
321 BlockEdgeMap &Successors, FlowFunction &Func) {}
322
323template <typename BT>
324inline bool SampleProfileInference<BT>::isExit(const BasicBlockT *BB) {
325 return BB->succ_empty();
326}
327
328} // end namespace llvm
329#endif // LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ABI
Definition Compiler.h:215
This file defines the DenseMap class.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file defines the SmallVector class.
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:258
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition DenseMap.h:254
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again.
Definition DenseMap.h:211
std::remove_pointer_t< NodeRef > BasicBlockT
DenseMap< const BasicBlockT *, uint64_t > BlockWeightMap
DenseMap< const BasicBlockT *, SmallVector< const BasicBlockT *, 8 > > BlockEdgeMap
typename GraphTraits< FT * >::NodeRef NodeRef
SampleProfileInference(FunctionT &F, BlockEdgeMap &Successors, BlockWeightMap &SampleBlockWeights, EdgeWeightMap &SampleEdgeWeights)
DenseMap< Edge, uint64_t > EdgeWeightMap
std::pair< const BasicBlockT *, const BasicBlockT * > Edge
void apply(BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights)
Apply the profile inference algorithm for a given function.
SampleProfileInference(FunctionT &F, BlockEdgeMap &Successors, BlockWeightMap &SampleBlockWeights)
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
bool contains(ConstPtrType Ptr) const
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< df_ext_iterator< T, SetTy > > depth_first_ext(const T &G, SetTy &S)
iterator_range< idf_ext_iterator< T, SetTy > > inverse_depth_first_ext(const T &G, SetTy &S)
LLVM_ABI void applyFlowInference(const ProfiParams &Params, FlowFunction &Func)
Apply the profile inference algorithm for a given function and provided profi options.
A wrapper of a binary basic block.
bool isEntry() const
Check if it is the entry block in the function.
bool isExit() const
Check if it is an exit block in the function.
std::vector< FlowJump * > PredJumps
std::vector< FlowJump * > SuccJumps
A wrapper of binary function with basic blocks and jumps.
std::vector< FlowJump > Jumps
Jumps between the basic blocks.
std::vector< FlowBlock > Blocks
Basic blocks in the function.
uint64_t Entry
The index of the entry block.
A wrapper of a jump between two basic blocks.
typename GraphType::UnknownGraphTypeError NodeRef
Definition GraphTraits.h:95
Various thresholds and options controlling the behavior of the profile inference algorithm.
unsigned CostJumpUnknownFTInc
The cost of increasing an unknown fall-through jump's count by one.
unsigned CostBlockInc
The cost of increasing a block's count by one.
unsigned CostJumpFTInc
The cost of increasing a fall-through jump's count by one.
bool RebalanceUnknown
Evenly re-distribute flow among unknown subgraphs.
const int64_t CostUnlikely
The cost of taking an unlikely block/jump.
unsigned CostJumpDec
The cost of decreasing a jump's count by one.
bool JoinIslands
Join isolated components having positive flow.
unsigned CostBlockZeroInc
The cost of increasing a count of zero-weight block by one.
unsigned CostBlockEntryDec
The cost of decreasing the entry block's count by one.
unsigned CostJumpInc
The cost of increasing a jump's count by one.
unsigned CostJumpUnknownInc
The cost of increasing an unknown jump's count by one.
unsigned CostBlockUnknownInc
The cost of increasing an unknown block's count by one.
unsigned CostJumpFTDec
The cost of decreasing a fall-through jump's count by one.
unsigned CostBlockDec
The cost of decreasing a block's count by one.
unsigned CostBlockEntryInc
The cost of increasing the entry block's count by one.
bool EvenFlowDistribution
Evenly distribute flow when there are multiple equally likely options.