blob: a2e42bb3e639ad36c8faeda8805059485b9e4305 [file] [log] [blame]
Andrew Trick962318f62013-01-11 17:28:14 +00001//===- CallPrinter.cpp - DOT printer for call graph -----------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines '-dot-callgraph', which emit a callgraph.<fnname>.dot
11// containing the call graph of a module.
12//
13// There is also a pass available to directly call dotty ('-view-callgraph').
14//
15//===----------------------------------------------------------------------===//
16
Andrew Trick962318f62013-01-11 17:28:14 +000017#include "llvm/Analysis/CallPrinter.h"
Sean Fertile3b0535b2018-06-29 17:13:58 +000018
19#include "llvm/Analysis/BlockFrequencyInfo.h"
20#include "llvm/Analysis/BranchProbabilityInfo.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000021#include "llvm/Analysis/CallGraph.h"
Andrew Trick962318f62013-01-11 17:28:14 +000022#include "llvm/Analysis/DOTGraphTraitsPass.h"
Sean Fertile3b0535b2018-06-29 17:13:58 +000023#include "llvm/Analysis/HeatUtils.h"
24
25#include "llvm/ADT/DenseMap.h"
26#include "llvm/ADT/SmallSet.h"
Andrew Trick962318f62013-01-11 17:28:14 +000027
28using namespace llvm;
29
Sean Fertile3b0535b2018-06-29 17:13:58 +000030static cl::opt<bool> ShowHeatColors("callgraph-heat-colors", cl::init(true),
31 cl::Hidden,
32 cl::desc("Show heat colors in call-graph"));
33
34static cl::opt<bool>
35 EstimateEdgeWeight("callgraph-weights", cl::init(false), cl::Hidden,
36 cl::desc("Show edges labeled with weights"));
37
38static cl::opt<bool>
39 FullCallGraph("callgraph-full", cl::init(false), cl::Hidden,
40 cl::desc("Show full call-graph (including external nodes)"));
41
42static cl::opt<bool> UseCallCounter(
43 "callgraph-call-count", cl::init(false), cl::Hidden,
44 cl::desc("Use function's call counter as a heat metric. "
45 "The default is the function's maximum block frequency."));
46
Andrew Trick962318f62013-01-11 17:28:14 +000047namespace llvm {
48
Sean Fertile3b0535b2018-06-29 17:13:58 +000049class CallGraphDOTInfo {
50private:
51 Module *M;
52 CallGraph *CG;
53 DenseMap<const Function *, uint64_t> Freq;
54 uint64_t MaxFreq;
55 uint64_t MaxEdgeCount;
56
57public:
58 std::function<BlockFrequencyInfo *(Function &)> LookupBFI;
59
60 CallGraphDOTInfo(Module *M, CallGraph *CG,
61 function_ref<BlockFrequencyInfo *(Function &)> LookupBFI)
62 : M(M), CG(CG), LookupBFI(LookupBFI) {
63 MaxFreq = 0;
64 MaxEdgeCount = 0;
65
66 for (Function &F : *M) {
67 Freq[&F] = 0;
68
69 if (FullCallGraph) {
70 for (User *U : F.users()) {
71 auto CS = CallSite(U);
72 if (!CS.getCaller()->isDeclaration()) {
73 uint64_t Counter = getNumOfCalls(CS, LookupBFI);
74 if (Counter > MaxEdgeCount) {
75 MaxEdgeCount = Counter;
76 }
77 }
78 }
79 }
80
81 if (F.isDeclaration())
82 continue;
83 uint64_t localMaxFreq = 0;
84 if (UseCallCounter) {
85 Function::ProfileCount EntryCount = F.getEntryCount();
86 if (EntryCount.hasValue())
87 localMaxFreq = EntryCount.getCount();
88 } else {
89 localMaxFreq = llvm::getMaxFreq(F, LookupBFI(F));
90 }
91 if (localMaxFreq >= MaxFreq)
92 MaxFreq = localMaxFreq;
93 Freq[&F] = localMaxFreq;
94
95 if (!FullCallGraph) {
96 for (Function &Callee : *M) {
97 uint64_t Counter = getNumOfCalls(F, Callee, LookupBFI);
98 if (Counter > MaxEdgeCount) {
99 MaxEdgeCount = Counter;
100 }
101 }
102 }
103 }
104 if (!FullCallGraph)
105 removeParallelEdges();
106 }
107
108 Module *getModule() const { return M; }
109 CallGraph *getCallGraph() const { return CG; }
110
111 uint64_t getFreq(const Function *F) { return Freq[F]; }
112
113 uint64_t getMaxFreq() { return MaxFreq; }
114
115 uint64_t getMaxEdgeCount() { return MaxEdgeCount; }
116
117private:
118 void removeParallelEdges() {
119 for (auto &I : (*CG)) {
120 CallGraphNode *Node = I.second.get();
121
122 bool FoundParallelEdge = true;
123 while (FoundParallelEdge) {
124 SmallSet<Function *, 16> Visited;
125 FoundParallelEdge = false;
126 for (auto CI = Node->begin(), CE = Node->end(); CI != CE; CI++) {
127 if (!Visited.count(CI->second->getFunction()))
128 Visited.insert(CI->second->getFunction());
129 else {
130 FoundParallelEdge = true;
131 Node->removeCallEdge(CI);
132 break;
133 }
134 }
135 }
136 }
137 }
138};
139
140template <>
141struct GraphTraits<CallGraphDOTInfo *>
142 : public GraphTraits<const CallGraphNode *> {
143 static NodeRef getEntryNode(CallGraphDOTInfo *CGInfo) {
144 // Start at the external node!
145 return CGInfo->getCallGraph()->getExternalCallingNode();
146 }
147
148 typedef std::pair<const Function *const, std::unique_ptr<CallGraphNode>>
149 PairTy;
150 static const CallGraphNode *CGGetValuePtr(const PairTy &P) {
151 return P.second.get();
152 }
153
154 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
155 typedef mapped_iterator<CallGraph::const_iterator, decltype(&CGGetValuePtr)>
156 nodes_iterator;
157
158 static nodes_iterator nodes_begin(CallGraphDOTInfo *CGInfo) {
159 return nodes_iterator(CGInfo->getCallGraph()->begin(), &CGGetValuePtr);
160 }
161 static nodes_iterator nodes_end(CallGraphDOTInfo *CGInfo) {
162 return nodes_iterator(CGInfo->getCallGraph()->end(), &CGGetValuePtr);
163 }
164};
165
166template <>
167struct DOTGraphTraits<CallGraphDOTInfo *> : public DefaultDOTGraphTraits {
168
169 SmallSet<User *, 16> VisitedCallSites;
170
Chandler Carruth878b5532013-11-26 03:45:26 +0000171 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
Andrew Trick962318f62013-01-11 17:28:14 +0000172
Sean Fertile3b0535b2018-06-29 17:13:58 +0000173 static std::string getGraphName(CallGraphDOTInfo *CGInfo) {
174 return "Call graph: " +
175 std::string(CGInfo->getModule()->getModuleIdentifier());
176 }
Andrew Trick962318f62013-01-11 17:28:14 +0000177
Sean Fertile3b0535b2018-06-29 17:13:58 +0000178 static bool isNodeHidden(const CallGraphNode *Node) {
179 if (FullCallGraph)
180 return false;
181
182 if (Node->getFunction())
183 return false;
184
185 return true;
186 }
187
188 std::string getNodeLabel(const CallGraphNode *Node,
189 CallGraphDOTInfo *CGInfo) {
190 if (Node == CGInfo->getCallGraph()->getExternalCallingNode())
191 return "external caller";
192
193 if (Node == CGInfo->getCallGraph()->getCallsExternalNode())
194 return "external callee";
195
Andrew Trick962318f62013-01-11 17:28:14 +0000196 if (Function *Func = Node->getFunction())
197 return Func->getName();
198
199 return "external node";
200 }
Andrew Trick962318f62013-01-11 17:28:14 +0000201
Sean Fertile3b0535b2018-06-29 17:13:58 +0000202 static const CallGraphNode *CGGetValuePtr(CallGraphNode::CallRecord P) {
203 return P.second;
204 }
205
206 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
207 typedef mapped_iterator<CallGraphNode::const_iterator,
208 decltype(&CGGetValuePtr)>
209 nodes_iterator;
210
211 std::string getEdgeAttributes(const CallGraphNode *Node, nodes_iterator I,
212 CallGraphDOTInfo *CGInfo) {
213 if (!EstimateEdgeWeight)
214 return "";
215
216 Function *Caller = Node->getFunction();
217 if (Caller == nullptr || Caller->isDeclaration())
218 return "";
219
220 Function *Callee = (*I)->getFunction();
221 if (Callee == nullptr)
222 return "";
223
224 uint64_t Counter = 0;
225 if (FullCallGraph) {
226 // looks for next call site between Caller and Callee
227 for (User *U : Callee->users()) {
228 auto CS = CallSite(U);
229 if (CS.getCaller() == Caller) {
230 if (VisitedCallSites.count(U))
231 continue;
232 VisitedCallSites.insert(U);
233 Counter = getNumOfCalls(CS, CGInfo->LookupBFI);
234 break;
235 }
236 }
237 } else {
238 Counter = getNumOfCalls(*Caller, *Callee, CGInfo->LookupBFI);
239 }
240
241 const unsigned MaxEdgeWidth = 3;
242
243 double Width =
244 1 + (MaxEdgeWidth - 1) * (double(Counter) / CGInfo->getMaxEdgeCount());
245 std::string Attrs = "label=\"" + std::to_string(Counter) +
246 "\" penwidth=" + std::to_string(Width);
247
248 return Attrs;
249 }
250
251 std::string getNodeAttributes(const CallGraphNode *Node,
252 CallGraphDOTInfo *CGInfo) {
253 Function *F = Node->getFunction();
254 if (F == nullptr || F->isDeclaration())
255 return "";
256
257 std::string attrs = "";
258 if (ShowHeatColors) {
259 uint64_t freq = CGInfo->getFreq(F);
260 std::string color = getHeatColor(freq, CGInfo->getMaxFreq());
261 std::string edgeColor = (freq <= (CGInfo->getMaxFreq() / 2))
262 ? getHeatColor(0)
263 : getHeatColor(1);
264
265 attrs = "color=\"" + edgeColor + "ff\", style=filled, fillcolor=\"" +
266 color + "80\"";
267 }
268 return attrs;
Chandler Carruth6378cf52013-11-26 04:19:30 +0000269 }
270};
271
Sean Fertile3b0535b2018-06-29 17:13:58 +0000272} // namespace llvm
Andrew Trick962318f62013-01-11 17:28:14 +0000273
274namespace {
275
Sean Fertile3b0535b2018-06-29 17:13:58 +0000276// Viewer
Andrew Trick962318f62013-01-11 17:28:14 +0000277
Sean Fertile3b0535b2018-06-29 17:13:58 +0000278class CallGraphViewer : public ModulePass {
279public:
280 static char ID;
281 CallGraphViewer() : ModulePass(ID) {}
282
283 void getAnalysisUsage(AnalysisUsage &AU) const override;
284 bool runOnModule(Module &M) override;
Andrew Trick962318f62013-01-11 17:28:14 +0000285};
286
Sean Fertile3b0535b2018-06-29 17:13:58 +0000287void CallGraphViewer::getAnalysisUsage(AnalysisUsage &AU) const {
288 ModulePass::getAnalysisUsage(AU);
289 AU.addRequired<BlockFrequencyInfoWrapperPass>();
290 AU.setPreservesAll();
291}
Andrew Trick962318f62013-01-11 17:28:14 +0000292
Sean Fertile3b0535b2018-06-29 17:13:58 +0000293bool CallGraphViewer::runOnModule(Module &M) {
294 auto LookupBFI = [this](Function &F) {
295 return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
296 };
297
298 CallGraph CG(M);
299 CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
300
301 std::string Title =
302 DOTGraphTraits<CallGraphDOTInfo *>::getGraphName(&CFGInfo);
303 ViewGraph(&CFGInfo, "callgraph", true, Title);
304
305 return false;
306}
307
308// DOT Printer
309
310class CallGraphDOTPrinter : public ModulePass {
311public:
312 static char ID;
313 CallGraphDOTPrinter() : ModulePass(ID) {}
314
315 void getAnalysisUsage(AnalysisUsage &AU) const override;
316 bool runOnModule(Module &M) override;
Andrew Trick962318f62013-01-11 17:28:14 +0000317};
318
Sean Fertile3b0535b2018-06-29 17:13:58 +0000319void CallGraphDOTPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
320 ModulePass::getAnalysisUsage(AU);
321 AU.addRequired<BlockFrequencyInfoWrapperPass>();
322 AU.setPreservesAll();
323}
324
325bool CallGraphDOTPrinter::runOnModule(Module &M) {
326 auto LookupBFI = [this](Function &F) {
327 return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
328 };
329
330 std::string Filename =
331 (std::string(M.getModuleIdentifier()) + ".callgraph.dot");
332 errs() << "Writing '" << Filename << "'...";
333
334 std::error_code EC;
335 raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
336
337 CallGraph CG(M);
338 CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
339
340 if (!EC)
341 WriteGraph(File, &CFGInfo);
342 else
343 errs() << " error opening file for writing!";
344 errs() << "\n";
345
346 return false;
347}
348
Andrew Trick962318f62013-01-11 17:28:14 +0000349} // end anonymous namespace
350
351char CallGraphViewer::ID = 0;
Chandler Carruth878b5532013-11-26 03:45:26 +0000352INITIALIZE_PASS(CallGraphViewer, "view-callgraph", "View call graph", false,
353 false)
Andrew Trick962318f62013-01-11 17:28:14 +0000354
Chandler Carruth5f432292016-03-10 11:04:40 +0000355char CallGraphDOTPrinter::ID = 0;
356INITIALIZE_PASS(CallGraphDOTPrinter, "dot-callgraph",
Chandler Carruth878b5532013-11-26 03:45:26 +0000357 "Print call graph to 'dot' file", false, false)
Andrew Trick962318f62013-01-11 17:28:14 +0000358
359// Create methods available outside of this file, to use them
360// "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by
361// the link time optimization.
362
Chandler Carruth878b5532013-11-26 03:45:26 +0000363ModulePass *llvm::createCallGraphViewerPass() { return new CallGraphViewer(); }
Andrew Trick962318f62013-01-11 17:28:14 +0000364
Chandler Carruth5f432292016-03-10 11:04:40 +0000365ModulePass *llvm::createCallGraphDOTPrinterPass() {
366 return new CallGraphDOTPrinter();
Andrew Trick962318f62013-01-11 17:28:14 +0000367}