File indexing completed on 2026-05-10 08:44:40
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_TRANSFORMS_IPO_PROFILEDCALLGRAPH_H
0010 #define LLVM_TRANSFORMS_IPO_PROFILEDCALLGRAPH_H
0011
0012 #include "llvm/ADT/GraphTraits.h"
0013 #include "llvm/ProfileData/SampleProf.h"
0014 #include "llvm/ProfileData/SampleProfReader.h"
0015 #include "llvm/Transforms/IPO/SampleContextTracker.h"
0016 #include <queue>
0017 #include <set>
0018
0019 namespace llvm {
0020 namespace sampleprof {
0021
0022 struct ProfiledCallGraphNode;
0023
0024 struct ProfiledCallGraphEdge {
0025 ProfiledCallGraphEdge(ProfiledCallGraphNode *Source,
0026 ProfiledCallGraphNode *Target, uint64_t Weight)
0027 : Source(Source), Target(Target), Weight(Weight) {}
0028 ProfiledCallGraphNode *Source;
0029 ProfiledCallGraphNode *Target;
0030 uint64_t Weight;
0031
0032
0033
0034 operator ProfiledCallGraphNode *() const { return Target; }
0035 };
0036
0037 struct ProfiledCallGraphNode {
0038
0039
0040
0041
0042 struct ProfiledCallGraphEdgeComparer {
0043 bool operator()(const ProfiledCallGraphEdge &L,
0044 const ProfiledCallGraphEdge &R) const {
0045 return L.Target->Name < R.Target->Name;
0046 }
0047 };
0048
0049 using edge = ProfiledCallGraphEdge;
0050 using edges = std::set<edge, ProfiledCallGraphEdgeComparer>;
0051 using iterator = edges::iterator;
0052 using const_iterator = edges::const_iterator;
0053
0054 ProfiledCallGraphNode(FunctionId FName = FunctionId()) : Name(FName)
0055 {}
0056
0057 FunctionId Name;
0058 edges Edges;
0059 };
0060
0061 class ProfiledCallGraph {
0062 public:
0063 using iterator = ProfiledCallGraphNode::iterator;
0064
0065
0066 ProfiledCallGraph(SampleProfileMap &ProfileMap,
0067 uint64_t IgnoreColdCallThreshold = 0) {
0068 assert(!FunctionSamples::ProfileIsCS &&
0069 "CS flat profile is not handled here");
0070 for (const auto &Samples : ProfileMap) {
0071 addProfiledCalls(Samples.second);
0072 }
0073
0074
0075
0076 trimColdEges(IgnoreColdCallThreshold);
0077 }
0078
0079
0080 ProfiledCallGraph(SampleContextTracker &ContextTracker,
0081 uint64_t IgnoreColdCallThreshold = 0) {
0082
0083
0084 std::queue<ContextTrieNode *> Queue;
0085 for (auto &Child : ContextTracker.getRootContext().getAllChildContext()) {
0086 ContextTrieNode *Callee = &Child.second;
0087 addProfiledFunction(Callee->getFuncName());
0088 Queue.push(Callee);
0089 }
0090
0091 while (!Queue.empty()) {
0092 ContextTrieNode *Caller = Queue.front();
0093 Queue.pop();
0094 FunctionSamples *CallerSamples = Caller->getFunctionSamples();
0095
0096
0097
0098
0099
0100
0101
0102 for (auto &Child : Caller->getAllChildContext()) {
0103 ContextTrieNode *Callee = &Child.second;
0104 addProfiledFunction(Callee->getFuncName());
0105 Queue.push(Callee);
0106
0107
0108 uint64_t Weight;
0109 FunctionSamples *CalleeSamples = Callee->getFunctionSamples();
0110 if (!CalleeSamples || !CallerSamples) {
0111 Weight = 0;
0112 } else {
0113 uint64_t CalleeEntryCount = CalleeSamples->getHeadSamplesEstimate();
0114 uint64_t CallsiteCount = 0;
0115 LineLocation Callsite = Callee->getCallSiteLoc();
0116 if (auto CallTargets = CallerSamples->findCallTargetMapAt(Callsite)) {
0117 auto It = CallTargets->find(CalleeSamples->getFunction());
0118 if (It != CallTargets->end())
0119 CallsiteCount = It->second;
0120 }
0121 Weight = std::max(CallsiteCount, CalleeEntryCount);
0122 }
0123
0124 addProfiledCall(Caller->getFuncName(), Callee->getFuncName(), Weight);
0125 }
0126 }
0127
0128
0129
0130 trimColdEges(IgnoreColdCallThreshold);
0131 }
0132
0133 iterator begin() { return Root.Edges.begin(); }
0134 iterator end() { return Root.Edges.end(); }
0135 ProfiledCallGraphNode *getEntryNode() { return &Root; }
0136
0137 void addProfiledFunction(FunctionId Name) {
0138 if (!ProfiledFunctions.count(Name)) {
0139
0140
0141
0142 auto &Node =
0143 ProfiledCallGraphNodeList.emplace_back(ProfiledCallGraphNode(Name));
0144 ProfiledFunctions[Name] = &Node;
0145 Root.Edges.emplace(&Root, ProfiledFunctions[Name], 0);
0146 }
0147 }
0148
0149 private:
0150 void addProfiledCall(FunctionId CallerName, FunctionId CalleeName,
0151 uint64_t Weight = 0) {
0152 assert(ProfiledFunctions.count(CallerName));
0153 auto CalleeIt = ProfiledFunctions.find(CalleeName);
0154 if (CalleeIt == ProfiledFunctions.end())
0155 return;
0156 ProfiledCallGraphEdge Edge(ProfiledFunctions[CallerName],
0157 CalleeIt->second, Weight);
0158 auto &Edges = ProfiledFunctions[CallerName]->Edges;
0159 auto [EdgeIt, Inserted] = Edges.insert(Edge);
0160 if (!Inserted) {
0161
0162 Edge.Weight += EdgeIt->Weight;
0163 Edges.erase(EdgeIt);
0164 Edges.insert(Edge);
0165 }
0166 }
0167
0168 void addProfiledCalls(const FunctionSamples &Samples) {
0169 addProfiledFunction(Samples.getFunction());
0170
0171 for (const auto &Sample : Samples.getBodySamples()) {
0172 for (const auto &[Target, Frequency] : Sample.second.getCallTargets()) {
0173 addProfiledFunction(Target);
0174 addProfiledCall(Samples.getFunction(), Target, Frequency);
0175 }
0176 }
0177
0178 for (const auto &CallsiteSamples : Samples.getCallsiteSamples()) {
0179 for (const auto &InlinedSamples : CallsiteSamples.second) {
0180 addProfiledFunction(InlinedSamples.first);
0181 addProfiledCall(Samples.getFunction(), InlinedSamples.first,
0182 InlinedSamples.second.getHeadSamplesEstimate());
0183 addProfiledCalls(InlinedSamples.second);
0184 }
0185 }
0186 }
0187
0188
0189
0190 void trimColdEges(uint64_t Threshold = 0) {
0191 if (!Threshold)
0192 return;
0193
0194 for (auto &Node : ProfiledFunctions) {
0195 auto &Edges = Node.second->Edges;
0196 auto I = Edges.begin();
0197 while (I != Edges.end()) {
0198 if (I->Weight <= Threshold)
0199 I = Edges.erase(I);
0200 else
0201 I++;
0202 }
0203 }
0204 }
0205
0206 ProfiledCallGraphNode Root;
0207
0208 std::list<ProfiledCallGraphNode> ProfiledCallGraphNodeList;
0209 HashKeyMap<llvm::DenseMap, FunctionId, ProfiledCallGraphNode*>
0210 ProfiledFunctions;
0211 };
0212
0213 }
0214
0215 template <> struct GraphTraits<ProfiledCallGraphNode *> {
0216 using NodeType = ProfiledCallGraphNode;
0217 using NodeRef = ProfiledCallGraphNode *;
0218 using EdgeType = NodeType::edge;
0219 using ChildIteratorType = NodeType::const_iterator;
0220
0221 static NodeRef getEntryNode(NodeRef PCGN) { return PCGN; }
0222 static ChildIteratorType child_begin(NodeRef N) { return N->Edges.begin(); }
0223 static ChildIteratorType child_end(NodeRef N) { return N->Edges.end(); }
0224 };
0225
0226 template <>
0227 struct GraphTraits<ProfiledCallGraph *>
0228 : public GraphTraits<ProfiledCallGraphNode *> {
0229 static NodeRef getEntryNode(ProfiledCallGraph *PCG) {
0230 return PCG->getEntryNode();
0231 }
0232
0233 static ChildIteratorType nodes_begin(ProfiledCallGraph *PCG) {
0234 return PCG->begin();
0235 }
0236
0237 static ChildIteratorType nodes_end(ProfiledCallGraph *PCG) {
0238 return PCG->end();
0239 }
0240 };
0241
0242 }
0243
0244 #endif