SampleContextTracker.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- Transforms/IPO/SampleContextTracker.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 context-sensitive profile tracker used
  16. /// by CSSPGO.
  17. //
  18. //===----------------------------------------------------------------------===//
  19. #ifndef LLVM_TRANSFORMS_IPO_SAMPLECONTEXTTRACKER_H
  20. #define LLVM_TRANSFORMS_IPO_SAMPLECONTEXTTRACKER_H
  21. #include "llvm/ADT/StringMap.h"
  22. #include "llvm/ADT/StringRef.h"
  23. #include "llvm/ADT/iterator.h"
  24. #include "llvm/ProfileData/SampleProf.h"
  25. #include <map>
  26. #include <queue>
  27. #include <vector>
  28. namespace llvm {
  29. class CallBase;
  30. class DILocation;
  31. class Function;
  32. class Instruction;
  33. // Internal trie tree representation used for tracking context tree and sample
  34. // profiles. The path from root node to a given node represents the context of
  35. // that nodes' profile.
  36. class ContextTrieNode {
  37. public:
  38. ContextTrieNode(ContextTrieNode *Parent = nullptr,
  39. StringRef FName = StringRef(),
  40. FunctionSamples *FSamples = nullptr,
  41. LineLocation CallLoc = {0, 0})
  42. : ParentContext(Parent), FuncName(FName), FuncSamples(FSamples),
  43. CallSiteLoc(CallLoc){};
  44. ContextTrieNode *getChildContext(const LineLocation &CallSite,
  45. StringRef ChildName);
  46. ContextTrieNode *getHottestChildContext(const LineLocation &CallSite);
  47. ContextTrieNode *getOrCreateChildContext(const LineLocation &CallSite,
  48. StringRef ChildName,
  49. bool AllowCreate = true);
  50. void removeChildContext(const LineLocation &CallSite, StringRef ChildName);
  51. std::map<uint64_t, ContextTrieNode> &getAllChildContext();
  52. StringRef getFuncName() const;
  53. FunctionSamples *getFunctionSamples() const;
  54. void setFunctionSamples(FunctionSamples *FSamples);
  55. std::optional<uint32_t> getFunctionSize() const;
  56. void addFunctionSize(uint32_t FSize);
  57. LineLocation getCallSiteLoc() const;
  58. ContextTrieNode *getParentContext() const;
  59. void setParentContext(ContextTrieNode *Parent);
  60. void setCallSiteLoc(const LineLocation &Loc);
  61. void dumpNode();
  62. void dumpTree();
  63. private:
  64. // Map line+discriminator location to child context
  65. std::map<uint64_t, ContextTrieNode> AllChildContext;
  66. // Link to parent context node
  67. ContextTrieNode *ParentContext;
  68. // Function name for current context
  69. StringRef FuncName;
  70. // Function Samples for current context
  71. FunctionSamples *FuncSamples;
  72. // Function size for current context
  73. std::optional<uint32_t> FuncSize;
  74. // Callsite location in parent context
  75. LineLocation CallSiteLoc;
  76. };
  77. // Profile tracker that manages profiles and its associated context. It
  78. // provides interfaces used by sample profile loader to query context profile or
  79. // base profile for given function or location; it also manages context tree
  80. // manipulation that is needed to accommodate inline decisions so we have
  81. // accurate post-inline profile for functions. Internally context profiles
  82. // are organized in a trie, with each node representing profile for specific
  83. // calling context and the context is identified by path from root to the node.
  84. class SampleContextTracker {
  85. public:
  86. using ContextSamplesTy = std::vector<FunctionSamples *>;
  87. SampleContextTracker() = default;
  88. SampleContextTracker(SampleProfileMap &Profiles,
  89. const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap);
  90. // Populate the FuncToCtxtProfiles map after the trie is built.
  91. void populateFuncToCtxtMap();
  92. // Query context profile for a specific callee with given name at a given
  93. // call-site. The full context is identified by location of call instruction.
  94. FunctionSamples *getCalleeContextSamplesFor(const CallBase &Inst,
  95. StringRef CalleeName);
  96. // Get samples for indirect call targets for call site at given location.
  97. std::vector<const FunctionSamples *>
  98. getIndirectCalleeContextSamplesFor(const DILocation *DIL);
  99. // Query context profile for a given location. The full context
  100. // is identified by input DILocation.
  101. FunctionSamples *getContextSamplesFor(const DILocation *DIL);
  102. // Query context profile for a given sample contxt of a function.
  103. FunctionSamples *getContextSamplesFor(const SampleContext &Context);
  104. // Get all context profile for given function.
  105. ContextSamplesTy &getAllContextSamplesFor(const Function &Func);
  106. ContextSamplesTy &getAllContextSamplesFor(StringRef Name);
  107. ContextTrieNode *getOrCreateContextPath(const SampleContext &Context,
  108. bool AllowCreate);
  109. // Query base profile for a given function. A base profile is a merged view
  110. // of all context profiles for contexts that are not inlined.
  111. FunctionSamples *getBaseSamplesFor(const Function &Func,
  112. bool MergeContext = true);
  113. // Query base profile for a given function by name.
  114. FunctionSamples *getBaseSamplesFor(StringRef Name, bool MergeContext = true);
  115. // Retrieve the context trie node for given profile context
  116. ContextTrieNode *getContextFor(const SampleContext &Context);
  117. // Get real function name for a given trie node.
  118. StringRef getFuncNameFor(ContextTrieNode *Node) const;
  119. // Mark a context profile as inlined when function is inlined.
  120. // This makes sure that inlined context profile will be excluded in
  121. // function's base profile.
  122. void markContextSamplesInlined(const FunctionSamples *InlinedSamples);
  123. ContextTrieNode &getRootContext();
  124. void promoteMergeContextSamplesTree(const Instruction &Inst,
  125. StringRef CalleeName);
  126. // Create a merged conext-less profile map.
  127. void createContextLessProfileMap(SampleProfileMap &ContextLessProfiles);
  128. ContextTrieNode *
  129. getContextNodeForProfile(const FunctionSamples *FSamples) const {
  130. auto I = ProfileToNodeMap.find(FSamples);
  131. if (I == ProfileToNodeMap.end())
  132. return nullptr;
  133. return I->second;
  134. }
  135. StringMap<ContextSamplesTy> &getFuncToCtxtProfiles() {
  136. return FuncToCtxtProfiles;
  137. }
  138. class Iterator : public llvm::iterator_facade_base<
  139. Iterator, std::forward_iterator_tag, ContextTrieNode *,
  140. std::ptrdiff_t, ContextTrieNode **, ContextTrieNode *> {
  141. std::queue<ContextTrieNode *> NodeQueue;
  142. public:
  143. explicit Iterator() = default;
  144. explicit Iterator(ContextTrieNode *Node) { NodeQueue.push(Node); }
  145. Iterator &operator++() {
  146. assert(!NodeQueue.empty() && "Iterator already at the end");
  147. ContextTrieNode *Node = NodeQueue.front();
  148. NodeQueue.pop();
  149. for (auto &It : Node->getAllChildContext())
  150. NodeQueue.push(&It.second);
  151. return *this;
  152. }
  153. bool operator==(const Iterator &Other) const {
  154. if (NodeQueue.empty() && Other.NodeQueue.empty())
  155. return true;
  156. if (NodeQueue.empty() || Other.NodeQueue.empty())
  157. return false;
  158. return NodeQueue.front() == Other.NodeQueue.front();
  159. }
  160. ContextTrieNode *operator*() const {
  161. assert(!NodeQueue.empty() && "Invalid access to end iterator");
  162. return NodeQueue.front();
  163. }
  164. };
  165. Iterator begin() { return Iterator(&RootContext); }
  166. Iterator end() { return Iterator(); }
  167. #ifndef NDEBUG
  168. // Get a context string from root to current node.
  169. std::string getContextString(const FunctionSamples &FSamples) const;
  170. std::string getContextString(ContextTrieNode *Node) const;
  171. #endif
  172. // Dump the internal context profile trie.
  173. void dump();
  174. private:
  175. ContextTrieNode *getContextFor(const DILocation *DIL);
  176. ContextTrieNode *getCalleeContextFor(const DILocation *DIL,
  177. StringRef CalleeName);
  178. ContextTrieNode *getTopLevelContextNode(StringRef FName);
  179. ContextTrieNode &addTopLevelContextNode(StringRef FName);
  180. ContextTrieNode &promoteMergeContextSamplesTree(ContextTrieNode &NodeToPromo);
  181. void mergeContextNode(ContextTrieNode &FromNode, ContextTrieNode &ToNode);
  182. ContextTrieNode &
  183. promoteMergeContextSamplesTree(ContextTrieNode &FromNode,
  184. ContextTrieNode &ToNodeParent);
  185. ContextTrieNode &moveContextSamples(ContextTrieNode &ToNodeParent,
  186. const LineLocation &CallSite,
  187. ContextTrieNode &&NodeToMove);
  188. void setContextNode(const FunctionSamples *FSample, ContextTrieNode *Node) {
  189. ProfileToNodeMap[FSample] = Node;
  190. }
  191. // Map from function name to context profiles (excluding base profile)
  192. StringMap<ContextSamplesTy> FuncToCtxtProfiles;
  193. // Map from current FunctionSample to the belonged context trie.
  194. std::unordered_map<const FunctionSamples *, ContextTrieNode *>
  195. ProfileToNodeMap;
  196. // Map from function guid to real function names. Only used in md5 mode.
  197. const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap;
  198. // Root node for context trie tree
  199. ContextTrieNode RootContext;
  200. };
  201. } // end namespace llvm
  202. #endif // LLVM_TRANSFORMS_IPO_SAMPLECONTEXTTRACKER_H
  203. #ifdef __GNUC__
  204. #pragma GCC diagnostic pop
  205. #endif