123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- //===- CallPrinter.cpp - DOT printer for call graph -----------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines '-dot-callgraph', which emit a callgraph.<fnname>.dot
- // containing the call graph of a module.
- //
- // There is also a pass available to directly call dotty ('-view-callgraph').
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/Analysis/CallPrinter.h"
- #include "llvm/Analysis/BlockFrequencyInfo.h"
- #include "llvm/Analysis/BranchProbabilityInfo.h"
- #include "llvm/Analysis/CallGraph.h"
- #include "llvm/Analysis/DOTGraphTraitsPass.h"
- #include "llvm/Analysis/HeatUtils.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/InitializePasses.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/SmallSet.h"
- using namespace llvm;
- // This option shows static (relative) call counts.
- // FIXME:
- // Need to show real counts when profile data is available
- static cl::opt<bool> ShowHeatColors("callgraph-heat-colors", cl::init(false),
- cl::Hidden,
- cl::desc("Show heat colors in call-graph"));
- static cl::opt<bool>
- ShowEdgeWeight("callgraph-show-weights", cl::init(false), cl::Hidden,
- cl::desc("Show edges labeled with weights"));
- static cl::opt<bool>
- CallMultiGraph("callgraph-multigraph", cl::init(false), cl::Hidden,
- cl::desc("Show call-multigraph (do not remove parallel edges)"));
- static cl::opt<std::string> CallGraphDotFilenamePrefix(
- "callgraph-dot-filename-prefix", cl::Hidden,
- cl::desc("The prefix used for the CallGraph dot file names."));
- namespace llvm {
- class CallGraphDOTInfo {
- private:
- Module *M;
- CallGraph *CG;
- DenseMap<const Function *, uint64_t> Freq;
- uint64_t MaxFreq;
- public:
- std::function<BlockFrequencyInfo *(Function &)> LookupBFI;
- CallGraphDOTInfo(Module *M, CallGraph *CG,
- function_ref<BlockFrequencyInfo *(Function &)> LookupBFI)
- : M(M), CG(CG), LookupBFI(LookupBFI) {
- MaxFreq = 0;
- for (Function &F : M->getFunctionList()) {
- uint64_t localSumFreq = 0;
- SmallSet<Function *, 16> Callers;
- for (User *U : F.users())
- if (isa<CallInst>(U))
- Callers.insert(cast<Instruction>(U)->getFunction());
- for (Function *Caller : Callers)
- localSumFreq += getNumOfCalls(*Caller, F);
- if (localSumFreq >= MaxFreq)
- MaxFreq = localSumFreq;
- Freq[&F] = localSumFreq;
- }
- if (!CallMultiGraph)
- removeParallelEdges();
- }
- Module *getModule() const { return M; }
- CallGraph *getCallGraph() const { return CG; }
- uint64_t getFreq(const Function *F) { return Freq[F]; }
- uint64_t getMaxFreq() { return MaxFreq; }
- private:
- void removeParallelEdges() {
- for (auto &I : (*CG)) {
- CallGraphNode *Node = I.second.get();
- bool FoundParallelEdge = true;
- while (FoundParallelEdge) {
- SmallSet<Function *, 16> Visited;
- FoundParallelEdge = false;
- for (auto CI = Node->begin(), CE = Node->end(); CI != CE; CI++) {
- if (!(Visited.insert(CI->second->getFunction())).second) {
- FoundParallelEdge = true;
- Node->removeCallEdge(CI);
- break;
- }
- }
- }
- }
- }
- };
- template <>
- struct GraphTraits<CallGraphDOTInfo *>
- : public GraphTraits<const CallGraphNode *> {
- static NodeRef getEntryNode(CallGraphDOTInfo *CGInfo) {
- // Start at the external node!
- return CGInfo->getCallGraph()->getExternalCallingNode();
- }
- typedef std::pair<const Function *const, std::unique_ptr<CallGraphNode>>
- PairTy;
- static const CallGraphNode *CGGetValuePtr(const PairTy &P) {
- return P.second.get();
- }
- // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
- typedef mapped_iterator<CallGraph::const_iterator, decltype(&CGGetValuePtr)>
- nodes_iterator;
- static nodes_iterator nodes_begin(CallGraphDOTInfo *CGInfo) {
- return nodes_iterator(CGInfo->getCallGraph()->begin(), &CGGetValuePtr);
- }
- static nodes_iterator nodes_end(CallGraphDOTInfo *CGInfo) {
- return nodes_iterator(CGInfo->getCallGraph()->end(), &CGGetValuePtr);
- }
- };
- template <>
- struct DOTGraphTraits<CallGraphDOTInfo *> : public DefaultDOTGraphTraits {
- DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
- static std::string getGraphName(CallGraphDOTInfo *CGInfo) {
- return "Call graph: " +
- std::string(CGInfo->getModule()->getModuleIdentifier());
- }
- static bool isNodeHidden(const CallGraphNode *Node,
- const CallGraphDOTInfo *CGInfo) {
- if (CallMultiGraph || Node->getFunction())
- return false;
- return true;
- }
- std::string getNodeLabel(const CallGraphNode *Node,
- CallGraphDOTInfo *CGInfo) {
- if (Node == CGInfo->getCallGraph()->getExternalCallingNode())
- return "external caller";
- if (Node == CGInfo->getCallGraph()->getCallsExternalNode())
- return "external callee";
- if (Function *Func = Node->getFunction())
- return std::string(Func->getName());
- return "external node";
- }
- static const CallGraphNode *CGGetValuePtr(CallGraphNode::CallRecord P) {
- return P.second;
- }
- // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
- typedef mapped_iterator<CallGraphNode::const_iterator,
- decltype(&CGGetValuePtr)>
- nodes_iterator;
- std::string getEdgeAttributes(const CallGraphNode *Node, nodes_iterator I,
- CallGraphDOTInfo *CGInfo) {
- if (!ShowEdgeWeight)
- return "";
- Function *Caller = Node->getFunction();
- if (Caller == nullptr || Caller->isDeclaration())
- return "";
- Function *Callee = (*I)->getFunction();
- if (Callee == nullptr)
- return "";
- uint64_t Counter = getNumOfCalls(*Caller, *Callee);
- double Width =
- 1 + 2 * (double(Counter) / CGInfo->getMaxFreq());
- std::string Attrs = "label=\"" + std::to_string(Counter) +
- "\" penwidth=" + std::to_string(Width);
- return Attrs;
- }
- std::string getNodeAttributes(const CallGraphNode *Node,
- CallGraphDOTInfo *CGInfo) {
- Function *F = Node->getFunction();
- if (F == nullptr)
- return "";
- std::string attrs;
- if (ShowHeatColors) {
- uint64_t freq = CGInfo->getFreq(F);
- std::string color = getHeatColor(freq, CGInfo->getMaxFreq());
- std::string edgeColor = (freq <= (CGInfo->getMaxFreq() / 2))
- ? getHeatColor(0)
- : getHeatColor(1);
- attrs = "color=\"" + edgeColor + "ff\", style=filled, fillcolor=\"" +
- color + "80\"";
- }
- return attrs;
- }
- };
- } // end llvm namespace
- namespace {
- // Viewer
- class CallGraphViewer : public ModulePass {
- public:
- static char ID;
- CallGraphViewer() : ModulePass(ID) {}
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- bool runOnModule(Module &M) override;
- };
- void CallGraphViewer::getAnalysisUsage(AnalysisUsage &AU) const {
- ModulePass::getAnalysisUsage(AU);
- AU.addRequired<BlockFrequencyInfoWrapperPass>();
- AU.setPreservesAll();
- }
- bool CallGraphViewer::runOnModule(Module &M) {
- auto LookupBFI = [this](Function &F) {
- return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
- };
- CallGraph CG(M);
- CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
- std::string Title =
- DOTGraphTraits<CallGraphDOTInfo *>::getGraphName(&CFGInfo);
- ViewGraph(&CFGInfo, "callgraph", true, Title);
- return false;
- }
- // DOT Printer
- class CallGraphDOTPrinter : public ModulePass {
- public:
- static char ID;
- CallGraphDOTPrinter() : ModulePass(ID) {}
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- bool runOnModule(Module &M) override;
- };
- void CallGraphDOTPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
- ModulePass::getAnalysisUsage(AU);
- AU.addRequired<BlockFrequencyInfoWrapperPass>();
- AU.setPreservesAll();
- }
- bool CallGraphDOTPrinter::runOnModule(Module &M) {
- auto LookupBFI = [this](Function &F) {
- return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI();
- };
- std::string Filename;
- if (!CallGraphDotFilenamePrefix.empty())
- Filename = (CallGraphDotFilenamePrefix + ".callgraph.dot");
- else
- Filename = (std::string(M.getModuleIdentifier()) + ".callgraph.dot");
- errs() << "Writing '" << Filename << "'...";
- std::error_code EC;
- raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
- CallGraph CG(M);
- CallGraphDOTInfo CFGInfo(&M, &CG, LookupBFI);
- if (!EC)
- WriteGraph(File, &CFGInfo);
- else
- errs() << " error opening file for writing!";
- errs() << "\n";
- return false;
- }
- } // end anonymous namespace
- char CallGraphViewer::ID = 0;
- INITIALIZE_PASS(CallGraphViewer, "view-callgraph", "View call graph", false,
- false)
- char CallGraphDOTPrinter::ID = 0;
- INITIALIZE_PASS(CallGraphDOTPrinter, "dot-callgraph",
- "Print call graph to 'dot' file", false, false)
- // Create methods available outside of this file, to use them
- // "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by
- // the link time optimization.
- ModulePass *llvm::createCallGraphViewerPass() { return new CallGraphViewer(); }
- ModulePass *llvm::createCallGraphDOTPrinterPass() {
- return new CallGraphDOTPrinter();
- }
|