ProfiledCallGraph.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- ProfiledCallGraph.h - Profiled Call Graph ----------------- 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. #ifndef LLVM_TRANSFORMS_IPO_PROFILEDCALLGRAPH_H
  14. #define LLVM_TRANSFORMS_IPO_PROFILEDCALLGRAPH_H
  15. #include "llvm/ADT/GraphTraits.h"
  16. #include "llvm/ADT/StringMap.h"
  17. #include "llvm/ADT/StringRef.h"
  18. #include "llvm/ProfileData/SampleProf.h"
  19. #include "llvm/ProfileData/SampleProfReader.h"
  20. #include "llvm/Transforms/IPO/SampleContextTracker.h"
  21. #include <queue>
  22. #include <set>
  23. namespace llvm {
  24. namespace sampleprof {
  25. struct ProfiledCallGraphNode;
  26. struct ProfiledCallGraphEdge {
  27. ProfiledCallGraphEdge(ProfiledCallGraphNode *Source,
  28. ProfiledCallGraphNode *Target, uint64_t Weight)
  29. : Source(Source), Target(Target), Weight(Weight) {}
  30. ProfiledCallGraphNode *Source;
  31. ProfiledCallGraphNode *Target;
  32. uint64_t Weight;
  33. // The call destination is the only important data here,
  34. // allow to transparently unwrap into it.
  35. operator ProfiledCallGraphNode *() const { return Target; }
  36. };
  37. struct ProfiledCallGraphNode {
  38. // Sort edges by callee names only since all edges to be compared are from
  39. // same caller. Edge weights are not considered either because for the same
  40. // callee only the edge with the largest weight is added to the edge set.
  41. struct ProfiledCallGraphEdgeComparer {
  42. bool operator()(const ProfiledCallGraphEdge &L,
  43. const ProfiledCallGraphEdge &R) const {
  44. return L.Target->Name < R.Target->Name;
  45. }
  46. };
  47. using edge = ProfiledCallGraphEdge;
  48. using edges = std::set<edge, ProfiledCallGraphEdgeComparer>;
  49. using iterator = edges::iterator;
  50. using const_iterator = edges::const_iterator;
  51. ProfiledCallGraphNode(StringRef FName = StringRef()) : Name(FName) {}
  52. StringRef Name;
  53. edges Edges;
  54. };
  55. class ProfiledCallGraph {
  56. public:
  57. using iterator = ProfiledCallGraphNode::iterator;
  58. // Constructor for non-CS profile.
  59. ProfiledCallGraph(SampleProfileMap &ProfileMap) {
  60. assert(!FunctionSamples::ProfileIsCS &&
  61. "CS flat profile is not handled here");
  62. for (const auto &Samples : ProfileMap) {
  63. addProfiledCalls(Samples.second);
  64. }
  65. }
  66. // Constructor for CS profile.
  67. ProfiledCallGraph(SampleContextTracker &ContextTracker) {
  68. // BFS traverse the context profile trie to add call edges for calls shown
  69. // in context.
  70. std::queue<ContextTrieNode *> Queue;
  71. for (auto &Child : ContextTracker.getRootContext().getAllChildContext()) {
  72. ContextTrieNode *Callee = &Child.second;
  73. addProfiledFunction(ContextTracker.getFuncNameFor(Callee));
  74. Queue.push(Callee);
  75. }
  76. while (!Queue.empty()) {
  77. ContextTrieNode *Caller = Queue.front();
  78. Queue.pop();
  79. FunctionSamples *CallerSamples = Caller->getFunctionSamples();
  80. // Add calls for context.
  81. // Note that callsite target samples are completely ignored since they can
  82. // conflict with the context edges, which are formed by context
  83. // compression during profile generation, for cyclic SCCs. This may
  84. // further result in an SCC order incompatible with the purely
  85. // context-based one, which may in turn block context-based inlining.
  86. for (auto &Child : Caller->getAllChildContext()) {
  87. ContextTrieNode *Callee = &Child.second;
  88. addProfiledFunction(ContextTracker.getFuncNameFor(Callee));
  89. Queue.push(Callee);
  90. // Fetch edge weight from the profile.
  91. uint64_t Weight;
  92. FunctionSamples *CalleeSamples = Callee->getFunctionSamples();
  93. if (!CalleeSamples || !CallerSamples) {
  94. Weight = 0;
  95. } else {
  96. uint64_t CalleeEntryCount = CalleeSamples->getHeadSamplesEstimate();
  97. uint64_t CallsiteCount = 0;
  98. LineLocation Callsite = Callee->getCallSiteLoc();
  99. if (auto CallTargets = CallerSamples->findCallTargetMapAt(Callsite)) {
  100. SampleRecord::CallTargetMap &TargetCounts = CallTargets.get();
  101. auto It = TargetCounts.find(CalleeSamples->getName());
  102. if (It != TargetCounts.end())
  103. CallsiteCount = It->second;
  104. }
  105. Weight = std::max(CallsiteCount, CalleeEntryCount);
  106. }
  107. addProfiledCall(ContextTracker.getFuncNameFor(Caller),
  108. ContextTracker.getFuncNameFor(Callee), Weight);
  109. }
  110. }
  111. }
  112. iterator begin() { return Root.Edges.begin(); }
  113. iterator end() { return Root.Edges.end(); }
  114. ProfiledCallGraphNode *getEntryNode() { return &Root; }
  115. void addProfiledFunction(StringRef Name) {
  116. if (!ProfiledFunctions.count(Name)) {
  117. // Link to synthetic root to make sure every node is reachable
  118. // from root. This does not affect SCC order.
  119. ProfiledFunctions[Name] = ProfiledCallGraphNode(Name);
  120. Root.Edges.emplace(&Root, &ProfiledFunctions[Name], 0);
  121. }
  122. }
  123. private:
  124. void addProfiledCall(StringRef CallerName, StringRef CalleeName,
  125. uint64_t Weight = 0) {
  126. assert(ProfiledFunctions.count(CallerName));
  127. auto CalleeIt = ProfiledFunctions.find(CalleeName);
  128. if (CalleeIt == ProfiledFunctions.end())
  129. return;
  130. ProfiledCallGraphEdge Edge(&ProfiledFunctions[CallerName],
  131. &CalleeIt->second, Weight);
  132. auto &Edges = ProfiledFunctions[CallerName].Edges;
  133. auto EdgeIt = Edges.find(Edge);
  134. if (EdgeIt == Edges.end()) {
  135. Edges.insert(Edge);
  136. } else if (EdgeIt->Weight < Edge.Weight) {
  137. // Replace existing call edges with same target but smaller weight.
  138. Edges.erase(EdgeIt);
  139. Edges.insert(Edge);
  140. }
  141. }
  142. void addProfiledCalls(const FunctionSamples &Samples) {
  143. addProfiledFunction(Samples.getFuncName());
  144. for (const auto &Sample : Samples.getBodySamples()) {
  145. for (const auto &[Target, Frequency] : Sample.second.getCallTargets()) {
  146. addProfiledFunction(Target);
  147. addProfiledCall(Samples.getFuncName(), Target, Frequency);
  148. }
  149. }
  150. for (const auto &CallsiteSamples : Samples.getCallsiteSamples()) {
  151. for (const auto &InlinedSamples : CallsiteSamples.second) {
  152. addProfiledFunction(InlinedSamples.first);
  153. addProfiledCall(Samples.getFuncName(), InlinedSamples.first,
  154. InlinedSamples.second.getHeadSamplesEstimate());
  155. addProfiledCalls(InlinedSamples.second);
  156. }
  157. }
  158. }
  159. ProfiledCallGraphNode Root;
  160. StringMap<ProfiledCallGraphNode> ProfiledFunctions;
  161. };
  162. } // end namespace sampleprof
  163. template <> struct GraphTraits<ProfiledCallGraphNode *> {
  164. using NodeType = ProfiledCallGraphNode;
  165. using NodeRef = ProfiledCallGraphNode *;
  166. using EdgeType = NodeType::edge;
  167. using ChildIteratorType = NodeType::const_iterator;
  168. static NodeRef getEntryNode(NodeRef PCGN) { return PCGN; }
  169. static ChildIteratorType child_begin(NodeRef N) { return N->Edges.begin(); }
  170. static ChildIteratorType child_end(NodeRef N) { return N->Edges.end(); }
  171. };
  172. template <>
  173. struct GraphTraits<ProfiledCallGraph *>
  174. : public GraphTraits<ProfiledCallGraphNode *> {
  175. static NodeRef getEntryNode(ProfiledCallGraph *PCG) {
  176. return PCG->getEntryNode();
  177. }
  178. static ChildIteratorType nodes_begin(ProfiledCallGraph *PCG) {
  179. return PCG->begin();
  180. }
  181. static ChildIteratorType nodes_end(ProfiledCallGraph *PCG) {
  182. return PCG->end();
  183. }
  184. };
  185. } // end namespace llvm
  186. #endif
  187. #ifdef __GNUC__
  188. #pragma GCC diagnostic pop
  189. #endif