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