ProfiledCallGraph.h 7.7 KB

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