Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

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