SampleProfileInference.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- Transforms/Utils/SampleProfileInference.h ----------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. /// \file
  15. /// This file provides the interface for the profile inference algorithm, profi.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
  19. #define LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
  20. #include "llvm/ADT/DenseMap.h"
  21. #include "llvm/ADT/DepthFirstIterator.h"
  22. #include "llvm/ADT/SmallVector.h"
  23. #include "llvm/IR/BasicBlock.h"
  24. #include "llvm/IR/Instruction.h"
  25. #include "llvm/IR/Instructions.h"
  26. namespace llvm {
  27. class Function;
  28. class MachineBasicBlock;
  29. class MachineFunction;
  30. namespace afdo_detail {
  31. template <class BlockT> struct TypeMap {};
  32. template <> struct TypeMap<BasicBlock> {
  33. using BasicBlockT = BasicBlock;
  34. using FunctionT = Function;
  35. };
  36. template <> struct TypeMap<MachineBasicBlock> {
  37. using BasicBlockT = MachineBasicBlock;
  38. using FunctionT = MachineFunction;
  39. };
  40. } // end namespace afdo_detail
  41. struct FlowJump;
  42. /// A wrapper of a binary basic block.
  43. struct FlowBlock {
  44. uint64_t Index;
  45. uint64_t Weight{0};
  46. bool HasUnknownWeight{true};
  47. bool IsUnlikely{false};
  48. uint64_t Flow{0};
  49. std::vector<FlowJump *> SuccJumps;
  50. std::vector<FlowJump *> PredJumps;
  51. /// Check if it is the entry block in the function.
  52. bool isEntry() const { return PredJumps.empty(); }
  53. /// Check if it is an exit block in the function.
  54. bool isExit() const { return SuccJumps.empty(); }
  55. };
  56. /// A wrapper of a jump between two basic blocks.
  57. struct FlowJump {
  58. uint64_t Source;
  59. uint64_t Target;
  60. uint64_t Weight{0};
  61. bool HasUnknownWeight{true};
  62. bool IsUnlikely{false};
  63. uint64_t Flow{0};
  64. };
  65. /// A wrapper of binary function with basic blocks and jumps.
  66. struct FlowFunction {
  67. /// Basic blocks in the function.
  68. std::vector<FlowBlock> Blocks;
  69. /// Jumps between the basic blocks.
  70. std::vector<FlowJump> Jumps;
  71. /// The index of the entry block.
  72. uint64_t Entry{0};
  73. };
  74. /// Various thresholds and options controlling the behavior of the profile
  75. /// inference algorithm. Default values are tuned for several large-scale
  76. /// applications, and can be modified via corresponding command-line flags.
  77. struct ProfiParams {
  78. /// Evenly distribute flow when there are multiple equally likely options.
  79. bool EvenFlowDistribution{false};
  80. /// Evenly re-distribute flow among unknown subgraphs.
  81. bool RebalanceUnknown{false};
  82. /// Join isolated components having positive flow.
  83. bool JoinIslands{false};
  84. /// The cost of increasing a block's count by one.
  85. unsigned CostBlockInc{0};
  86. /// The cost of decreasing a block's count by one.
  87. unsigned CostBlockDec{0};
  88. /// The cost of increasing a count of zero-weight block by one.
  89. unsigned CostBlockZeroInc{0};
  90. /// The cost of increasing the entry block's count by one.
  91. unsigned CostBlockEntryInc{0};
  92. /// The cost of decreasing the entry block's count by one.
  93. unsigned CostBlockEntryDec{0};
  94. /// The cost of increasing an unknown block's count by one.
  95. unsigned CostBlockUnknownInc{0};
  96. /// The cost of increasing a jump's count by one.
  97. unsigned CostJumpInc{0};
  98. /// The cost of increasing a fall-through jump's count by one.
  99. unsigned CostJumpFTInc{0};
  100. /// The cost of decreasing a jump's count by one.
  101. unsigned CostJumpDec{0};
  102. /// The cost of decreasing a fall-through jump's count by one.
  103. unsigned CostJumpFTDec{0};
  104. /// The cost of increasing an unknown jump's count by one.
  105. unsigned CostJumpUnknownInc{0};
  106. /// The cost of increasing an unknown fall-through jump's count by one.
  107. unsigned CostJumpUnknownFTInc{0};
  108. /// The cost of taking an unlikely block/jump.
  109. const int64_t CostUnlikely = ((int64_t)1) << 30;
  110. };
  111. void applyFlowInference(const ProfiParams &Params, FlowFunction &Func);
  112. void applyFlowInference(FlowFunction &Func);
  113. /// Sample profile inference pass.
  114. template <typename BT> class SampleProfileInference {
  115. public:
  116. using BasicBlockT = typename afdo_detail::TypeMap<BT>::BasicBlockT;
  117. using FunctionT = typename afdo_detail::TypeMap<BT>::FunctionT;
  118. using Edge = std::pair<const BasicBlockT *, const BasicBlockT *>;
  119. using BlockWeightMap = DenseMap<const BasicBlockT *, uint64_t>;
  120. using EdgeWeightMap = DenseMap<Edge, uint64_t>;
  121. using BlockEdgeMap =
  122. DenseMap<const BasicBlockT *, SmallVector<const BasicBlockT *, 8>>;
  123. SampleProfileInference(FunctionT &F, BlockEdgeMap &Successors,
  124. BlockWeightMap &SampleBlockWeights)
  125. : F(F), Successors(Successors), SampleBlockWeights(SampleBlockWeights) {}
  126. /// Apply the profile inference algorithm for a given function
  127. void apply(BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights);
  128. private:
  129. /// Initialize flow function blocks, jumps and misc metadata.
  130. void initFunction(FlowFunction &Func,
  131. const std::vector<const BasicBlockT *> &BasicBlocks,
  132. DenseMap<const BasicBlockT *, uint64_t> &BlockIndex);
  133. /// Try to infer branch probabilities mimicking implementation of
  134. /// BranchProbabilityInfo. Unlikely taken branches are marked so that the
  135. /// inference algorithm can avoid sending flow along corresponding edges.
  136. void findUnlikelyJumps(const std::vector<const BasicBlockT *> &BasicBlocks,
  137. BlockEdgeMap &Successors, FlowFunction &Func);
  138. /// Determine whether the block is an exit in the CFG.
  139. bool isExit(const BasicBlockT *BB);
  140. /// Function.
  141. const FunctionT &F;
  142. /// Successors for each basic block in the CFG.
  143. BlockEdgeMap &Successors;
  144. /// Map basic blocks to their sampled weights.
  145. BlockWeightMap &SampleBlockWeights;
  146. };
  147. template <typename BT>
  148. void SampleProfileInference<BT>::apply(BlockWeightMap &BlockWeights,
  149. EdgeWeightMap &EdgeWeights) {
  150. // Find all forwards reachable blocks which the inference algorithm will be
  151. // applied on.
  152. df_iterator_default_set<const BasicBlockT *> Reachable;
  153. for (auto *BB : depth_first_ext(&F, Reachable))
  154. (void)BB /* Mark all reachable blocks */;
  155. // Find all backwards reachable blocks which the inference algorithm will be
  156. // applied on.
  157. df_iterator_default_set<const BasicBlockT *> InverseReachable;
  158. for (const auto &BB : F) {
  159. // An exit block is a block without any successors.
  160. if (isExit(&BB)) {
  161. for (auto *RBB : inverse_depth_first_ext(&BB, InverseReachable))
  162. (void)RBB;
  163. }
  164. }
  165. // Keep a stable order for reachable blocks
  166. DenseMap<const BasicBlockT *, uint64_t> BlockIndex;
  167. std::vector<const BasicBlockT *> BasicBlocks;
  168. BlockIndex.reserve(Reachable.size());
  169. BasicBlocks.reserve(Reachable.size());
  170. for (const auto &BB : F) {
  171. if (Reachable.count(&BB) && InverseReachable.count(&BB)) {
  172. BlockIndex[&BB] = BasicBlocks.size();
  173. BasicBlocks.push_back(&BB);
  174. }
  175. }
  176. BlockWeights.clear();
  177. EdgeWeights.clear();
  178. bool HasSamples = false;
  179. for (const auto *BB : BasicBlocks) {
  180. auto It = SampleBlockWeights.find(BB);
  181. if (It != SampleBlockWeights.end() && It->second > 0) {
  182. HasSamples = true;
  183. BlockWeights[BB] = It->second;
  184. }
  185. }
  186. // Quit early for functions with a single block or ones w/o samples
  187. if (BasicBlocks.size() <= 1 || !HasSamples) {
  188. return;
  189. }
  190. // Create necessary objects
  191. FlowFunction Func;
  192. initFunction(Func, BasicBlocks, BlockIndex);
  193. // Create and apply the inference network model.
  194. applyFlowInference(Func);
  195. // Extract the resulting weights from the control flow
  196. // All weights are increased by one to avoid propagation errors introduced by
  197. // zero weights.
  198. for (const auto *BB : BasicBlocks) {
  199. BlockWeights[BB] = Func.Blocks[BlockIndex[BB]].Flow;
  200. }
  201. for (auto &Jump : Func.Jumps) {
  202. Edge E = std::make_pair(BasicBlocks[Jump.Source], BasicBlocks[Jump.Target]);
  203. EdgeWeights[E] = Jump.Flow;
  204. }
  205. #ifndef NDEBUG
  206. // Unreachable blocks and edges should not have a weight.
  207. for (auto &I : BlockWeights) {
  208. assert(Reachable.contains(I.first));
  209. assert(InverseReachable.contains(I.first));
  210. }
  211. for (auto &I : EdgeWeights) {
  212. assert(Reachable.contains(I.first.first) &&
  213. Reachable.contains(I.first.second));
  214. assert(InverseReachable.contains(I.first.first) &&
  215. InverseReachable.contains(I.first.second));
  216. }
  217. #endif
  218. }
  219. template <typename BT>
  220. void SampleProfileInference<BT>::initFunction(
  221. FlowFunction &Func, const std::vector<const BasicBlockT *> &BasicBlocks,
  222. DenseMap<const BasicBlockT *, uint64_t> &BlockIndex) {
  223. Func.Blocks.reserve(BasicBlocks.size());
  224. // Create FlowBlocks
  225. for (const auto *BB : BasicBlocks) {
  226. FlowBlock Block;
  227. if (SampleBlockWeights.find(BB) != SampleBlockWeights.end()) {
  228. Block.HasUnknownWeight = false;
  229. Block.Weight = SampleBlockWeights[BB];
  230. } else {
  231. Block.HasUnknownWeight = true;
  232. Block.Weight = 0;
  233. }
  234. Block.Index = Func.Blocks.size();
  235. Func.Blocks.push_back(Block);
  236. }
  237. // Create FlowEdges
  238. for (const auto *BB : BasicBlocks) {
  239. for (auto *Succ : Successors[BB]) {
  240. if (!BlockIndex.count(Succ))
  241. continue;
  242. FlowJump Jump;
  243. Jump.Source = BlockIndex[BB];
  244. Jump.Target = BlockIndex[Succ];
  245. Func.Jumps.push_back(Jump);
  246. }
  247. }
  248. for (auto &Jump : Func.Jumps) {
  249. uint64_t Src = Jump.Source;
  250. uint64_t Dst = Jump.Target;
  251. Func.Blocks[Src].SuccJumps.push_back(&Jump);
  252. Func.Blocks[Dst].PredJumps.push_back(&Jump);
  253. }
  254. // Try to infer probabilities of jumps based on the content of basic block
  255. findUnlikelyJumps(BasicBlocks, Successors, Func);
  256. // Find the entry block
  257. for (size_t I = 0; I < Func.Blocks.size(); I++) {
  258. if (Func.Blocks[I].isEntry()) {
  259. Func.Entry = I;
  260. break;
  261. }
  262. }
  263. assert(Func.Entry == 0 && "incorrect index of the entry block");
  264. // Pre-process data: make sure the entry weight is at least 1
  265. auto &EntryBlock = Func.Blocks[Func.Entry];
  266. if (EntryBlock.Weight == 0 && !EntryBlock.HasUnknownWeight) {
  267. EntryBlock.Weight = 1;
  268. EntryBlock.HasUnknownWeight = false;
  269. }
  270. }
  271. template <typename BT>
  272. inline void SampleProfileInference<BT>::findUnlikelyJumps(
  273. const std::vector<const BasicBlockT *> &BasicBlocks,
  274. BlockEdgeMap &Successors, FlowFunction &Func) {}
  275. template <>
  276. inline void SampleProfileInference<BasicBlock>::findUnlikelyJumps(
  277. const std::vector<const BasicBlockT *> &BasicBlocks,
  278. BlockEdgeMap &Successors, FlowFunction &Func) {
  279. for (auto &Jump : Func.Jumps) {
  280. const auto *BB = BasicBlocks[Jump.Source];
  281. const auto *Succ = BasicBlocks[Jump.Target];
  282. const Instruction *TI = BB->getTerminator();
  283. // Check if a block ends with InvokeInst and mark non-taken branch unlikely.
  284. // In that case block Succ should be a landing pad
  285. if (Successors[BB].size() == 2 && Successors[BB].back() == Succ) {
  286. if (isa<InvokeInst>(TI)) {
  287. Jump.IsUnlikely = true;
  288. }
  289. }
  290. const Instruction *SuccTI = Succ->getTerminator();
  291. // Check if the target block contains UnreachableInst and mark it unlikely
  292. if (SuccTI->getNumSuccessors() == 0) {
  293. if (isa<UnreachableInst>(SuccTI)) {
  294. Jump.IsUnlikely = true;
  295. }
  296. }
  297. }
  298. }
  299. template <typename BT>
  300. inline bool SampleProfileInference<BT>::isExit(const BasicBlockT *BB) {
  301. return BB->succ_empty();
  302. }
  303. template <>
  304. inline bool SampleProfileInference<BasicBlock>::isExit(const BasicBlock *BB) {
  305. return succ_empty(BB);
  306. }
  307. } // end namespace llvm
  308. #endif // LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
  309. #ifdef __GNUC__
  310. #pragma GCC diagnostic pop
  311. #endif