[llvm] 8b67853 - [CFGPrinter] Adding heat coloring to CFGPrinter
Kirill Naumov via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 8 13:00:18 PDT 2020
Author: Kirill Naumov
Date: 2020-04-08T19:59:51Z
New Revision: 8b67853a83c16f1e97a7bda02e3cceb37b1cd7db
URL: https://github.com/llvm/llvm-project/commit/8b67853a83c16f1e97a7bda02e3cceb37b1cd7db
DIFF: https://github.com/llvm/llvm-project/commit/8b67853a83c16f1e97a7bda02e3cceb37b1cd7db.diff
LOG: [CFGPrinter] Adding heat coloring to CFGPrinter
This patch introduces the heat coloring of the Control Flow Graph which is based
on the relative "hotness" of each BB. The patch is a part of sequence of three
patches, related to graphs Heat Coloring.
Reviewers: rcorcs, apilipenko, davidxl, sfertile, fedor.sergeev, eraman, bollu
Differential Revision: https://reviews.llvm.org/D77161
Added:
llvm/include/llvm/Analysis/HeatUtils.h
llvm/lib/Analysis/HeatUtils.cpp
llvm/test/Other/cfg-printer-branch-weights-percent.ll
llvm/test/Other/heat-colors-graphs.ll
Modified:
llvm/include/llvm/Analysis/CFGPrinter.h
llvm/lib/Analysis/CFGPrinter.cpp
llvm/lib/Analysis/CMakeLists.txt
llvm/test/Other/2007-06-05-PassID.ll
llvm/test/Other/cfg-printer-branch-weights.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/CFGPrinter.h b/llvm/include/llvm/Analysis/CFGPrinter.h
index 80a26cd733fd..9f2195369a7c 100644
--- a/llvm/include/llvm/Analysis/CFGPrinter.h
+++ b/llvm/include/llvm/Analysis/CFGPrinter.h
@@ -20,6 +20,7 @@
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
+#include "llvm/Analysis/HeatUtils.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
@@ -29,26 +30,22 @@
#include "llvm/Support/GraphWriter.h"
namespace llvm {
-class CFGViewerPass
- : public PassInfoMixin<CFGViewerPass> {
+class CFGViewerPass : public PassInfoMixin<CFGViewerPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
-class CFGOnlyViewerPass
- : public PassInfoMixin<CFGOnlyViewerPass> {
+class CFGOnlyViewerPass : public PassInfoMixin<CFGOnlyViewerPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
-class CFGPrinterPass
- : public PassInfoMixin<CFGPrinterPass> {
+class CFGPrinterPass : public PassInfoMixin<CFGPrinterPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
-class CFGOnlyPrinterPass
- : public PassInfoMixin<CFGOnlyPrinterPass> {
+class CFGOnlyPrinterPass : public PassInfoMixin<CFGOnlyPrinterPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
@@ -58,13 +55,20 @@ class DOTFuncInfo {
const Function *F;
const BlockFrequencyInfo *BFI;
const BranchProbabilityInfo *BPI;
+ uint64_t MaxFreq;
+ bool ShowHeat;
+ bool EdgeWeights;
+ bool RawWeights;
public:
- DOTFuncInfo(const Function *F) : DOTFuncInfo(F, nullptr, nullptr) {}
+ DOTFuncInfo(const Function *F) : DOTFuncInfo(F, nullptr, nullptr, 0) {}
DOTFuncInfo(const Function *F, const BlockFrequencyInfo *BFI,
- BranchProbabilityInfo *BPI)
- : F(F), BFI(BFI), BPI(BPI) {
+ BranchProbabilityInfo *BPI, uint64_t MaxFreq)
+ : F(F), BFI(BFI), BPI(BPI), MaxFreq(MaxFreq) {
+ ShowHeat = false;
+ EdgeWeights = true;
+ RawWeights = true;
}
const BlockFrequencyInfo *getBFI() { return BFI; }
@@ -72,6 +76,24 @@ class DOTFuncInfo {
const BranchProbabilityInfo *getBPI() { return BPI; }
const Function *getFunction() { return this->F; }
+
+ uint64_t getMaxFreq() { return MaxFreq; }
+
+ uint64_t getFreq(const BasicBlock *BB) {
+ return BFI->getBlockFreq(BB).getFrequency();
+ }
+
+ void setHeatColors(bool ShowHeat) { this->ShowHeat = ShowHeat; }
+
+ bool showHeatColors() { return ShowHeat; }
+
+ void setRawEdgeWeights(bool RawWeights) { this->RawWeights = RawWeights; }
+
+ bool useRawEdgeWeights() { return RawWeights; }
+
+ void setEdgeWeights(bool EdgeWeights) { this->EdgeWeights = EdgeWeights; }
+
+ bool showEdgeWeights() { return EdgeWeights; }
};
template <>
@@ -96,12 +118,13 @@ struct GraphTraits<DOTFuncInfo *> : public GraphTraits<const BasicBlock *> {
}
};
-template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
+template <>
+struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
// Cache for is hidden property
- llvm::DenseMap <const BasicBlock *, bool> isHiddenBasicBlock;
+ llvm::DenseMap<const BasicBlock *, bool> isHiddenBasicBlock;
- DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+ DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
static std::string getGraphName(DOTFuncInfo *CFGInfo) {
return "CFG for '" + CFGInfo->getFunction()->getName().str() + "' function";
@@ -131,22 +154,23 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
OS << *Node;
std::string OutStr = OS.str();
- if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
+ if (OutStr[0] == '\n')
+ OutStr.erase(OutStr.begin());
// Process string output to make it nicer...
unsigned ColNum = 0;
unsigned LastSpace = 0;
for (unsigned i = 0; i != OutStr.length(); ++i) {
- if (OutStr[i] == '\n') { // Left justify
+ if (OutStr[i] == '\n') { // Left justify
OutStr[i] = '\\';
- OutStr.insert(OutStr.begin()+i+1, 'l');
+ OutStr.insert(OutStr.begin() + i + 1, 'l');
ColNum = 0;
LastSpace = 0;
- } else if (OutStr[i] == ';') { // Delete comments!
- unsigned Idx = OutStr.find('\n', i+1); // Find end of line
- OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx);
+ } else if (OutStr[i] == ';') { // Delete comments!
+ unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
+ OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
--i;
- } else if (ColNum == MaxColumns) { // Wrap lines.
+ } else if (ColNum == MaxColumns) { // Wrap lines.
// Wrap very long names even though we can't find a space.
if (!LastSpace)
LastSpace = i;
@@ -154,8 +178,7 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
ColNum = i - LastSpace;
LastSpace = 0;
i += 3; // The loop will advance 'i' again.
- }
- else
+ } else
++ColNum;
if (OutStr[i] == ' ')
LastSpace = i;
@@ -163,8 +186,7 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
return OutStr;
}
- std::string getNodeLabel(const BasicBlock *Node,
- DOTFuncInfo *CFGInfo) {
+ std::string getNodeLabel(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
if (isSimple())
return getSimpleNodeLabel(Node, CFGInfo);
@@ -183,7 +205,8 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
if (const SwitchInst *SI = dyn_cast<SwitchInst>(Node->getTerminator())) {
unsigned SuccNo = I.getSuccessorIndex();
- if (SuccNo == 0) return "def";
+ if (SuccNo == 0)
+ return "def";
std::string Str;
raw_string_ostream OS(Str);
@@ -197,9 +220,37 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
/// Display the raw branch weights from PGO.
std::string getEdgeAttributes(const BasicBlock *Node, const_succ_iterator I,
DOTFuncInfo *CFGInfo) {
+ if (!CFGInfo->showEdgeWeights())
+ return "";
+
const Instruction *TI = Node->getTerminator();
if (TI->getNumSuccessors() == 1)
+ return "penwidth=2";
+
+ unsigned OpNo = I.getSuccessorIndex();
+
+ if (OpNo >= TI->getNumSuccessors())
return "";
+
+ BasicBlock *SuccBB = TI->getSuccessor(OpNo);
+ auto BranchProb = CFGInfo->getBPI()->getEdgeProbability(Node, SuccBB);
+ double WeightPercent = ((double)BranchProb.getNumerator()) /
+ ((double)BranchProb.getDenominator());
+ double Width = 1 + WeightPercent;
+
+ if (!CFGInfo->useRawEdgeWeights())
+ return formatv("label=\"{0:P}\" penwidth={1}", WeightPercent, Width)
+ .str();
+
+ // Prepend a 'W' to indicate that this is a weight rather than the actual
+ // profile count (due to scaling).
+
+ uint64_t Freq = CFGInfo->getFreq(Node);
+ std::string Attrs = formatv("label=\"W:{0}\" penwidth={1}",
+ (uint64_t)(Freq * WeightPercent), Width);
+ if (Attrs.size())
+ return Attrs;
+
MDNode *WeightsNode = TI->getMetadata(LLVMContext::MD_prof);
if (!WeightsNode)
return "";
@@ -207,17 +258,32 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
MDString *MDName = cast<MDString>(WeightsNode->getOperand(0));
if (MDName->getString() != "branch_weights")
return "";
- unsigned OpNo = I.getSuccessorIndex() + 1;
+
+ OpNo = I.getSuccessorIndex() + 1;
if (OpNo >= WeightsNode->getNumOperands())
return "";
ConstantInt *Weight =
mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(OpNo));
if (!Weight)
return "";
+ return ("label=\"W:" + std::to_string(Weight->getZExtValue()) +
+ "\" penwidth=" + std::to_string(Width));
+ }
- // Prepend a 'W' to indicate that this is a weight rather than the actual
- // profile count (due to scaling).
- return ("label=\"W:" + Twine(Weight->getZExtValue()) + "\"").str();
+ std::string getNodeAttributes(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
+
+ if (!CFGInfo->showHeatColors())
+ return "";
+
+ uint64_t Freq = CFGInfo->getFreq(Node);
+ std::string Color = getHeatColor(Freq, CFGInfo->getMaxFreq());
+ std::string EdgeColor = (Freq <= (CFGInfo->getMaxFreq() / 2))
+ ? (getHeatColor(0))
+ : (getHeatColor(1));
+
+ std::string Attrs = "color=\"" + EdgeColor + "ff\", style=filled," +
+ " fillcolor=\"" + Color + "70\"";
+ return Attrs;
}
bool isNodeHidden(const BasicBlock *Node);
void computeHiddenNodes(const Function *F);
@@ -225,9 +291,9 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
} // End llvm namespace
namespace llvm {
- class FunctionPass;
- FunctionPass *createCFGPrinterLegacyPassPass ();
- FunctionPass *createCFGOnlyPrinterLegacyPassPass ();
+class FunctionPass;
+FunctionPass *createCFGPrinterLegacyPassPass();
+FunctionPass *createCFGOnlyPrinterLegacyPassPass();
} // End llvm namespace
#endif
diff --git a/llvm/include/llvm/Analysis/HeatUtils.h b/llvm/include/llvm/Analysis/HeatUtils.h
new file mode 100644
index 000000000000..ed6044c422a2
--- /dev/null
+++ b/llvm/include/llvm/Analysis/HeatUtils.h
@@ -0,0 +1,38 @@
+//===-- HeatUtils.h - Utility for printing heat colors ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for printing heat colors based on profiling information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_HEATUTILS_H
+#define LLVM_ANALYSIS_HEATUTILS_H
+
+#include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CallSite.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+
+#include <string>
+
+namespace llvm {
+
+// Returns the maximum frequency of a BB in a function.
+uint64_t getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI);
+
+// Calculates heat color based on current and maximum frequencies.
+std::string getHeatColor(uint64_t freq, uint64_t maxFreq);
+
+// Calculates heat color based on percent of "hotness".
+std::string getHeatColor(double percent);
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Analysis/CFGPrinter.cpp b/llvm/lib/Analysis/CFGPrinter.cpp
index 295d936c026e..7856b9731753 100644
--- a/llvm/lib/Analysis/CFGPrinter.cpp
+++ b/llvm/lib/Analysis/CFGPrinter.cpp
@@ -17,8 +17,8 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/Analysis/CFGPrinter.h"
+#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
@@ -27,24 +27,37 @@
using namespace llvm;
-static cl::opt<std::string> CFGFuncName(
- "cfg-func-name", cl::Hidden,
- cl::desc("The name of a function (or its substring)"
- " whose CFG is viewed/printed."));
+static cl::opt<std::string>
+ CFGFuncName("cfg-func-name", cl::Hidden,
+ cl::desc("The name of a function (or its substring)"
+ " whose CFG is viewed/printed."));
static cl::opt<std::string> CFGDotFilenamePrefix(
"cfg-dot-filename-prefix", cl::Hidden,
cl::desc("The prefix used for the CFG dot file names."));
static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths",
- cl::init(false));
+ cl::init(false));
static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths",
- cl::init(false));
+ cl::init(false));
+
+static cl::opt<bool> ShowHeatColors("cfg-heat-colors", cl::init(false),
+ cl::Hidden,
+ cl::desc("Show heat colors in CFG"));
+
+static cl::opt<bool> UseRawEdgeWeight("cfg-raw-weights", cl::init(false),
+ cl::Hidden,
+ cl::desc("Use raw weights for labels. "
+ "Use percentages as default."));
+
+static cl::opt<bool>
+ ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden,
+ cl::desc("Show edges labeled with weights"));
static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
- BranchProbabilityInfo *BPI,
- bool isSimple) {
+ BranchProbabilityInfo *BPI, uint64_t MaxFreq,
+ bool CFGOnly = false) {
std::string Filename =
(CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
errs() << "Writing '" << Filename << "'...";
@@ -52,81 +65,88 @@ static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
std::error_code EC;
raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
- DOTFuncInfo CFGInfo(&F, BFI, BPI);
+ DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
+ CFGInfo.setHeatColors(ShowHeatColors);
+ CFGInfo.setEdgeWeights(ShowEdgeWeight);
+ CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
+
if (!EC)
- WriteGraph(File, &CFGInfo, isSimple);
+ WriteGraph(File, &CFGInfo, CFGOnly);
else
errs() << " error opening file for writing!";
errs() << "\n";
}
static void viewCFG(Function &F, BlockFrequencyInfo *BFI,
- BranchProbabilityInfo *BPI,
- bool isSimple) {
- DOTFuncInfo CFGInfo(&F, BFI, BPI);
- ViewGraph(&CFGInfo, "cfg." + F.getName(), isSimple);
+ BranchProbabilityInfo *BPI, uint64_t MaxFreq,
+ bool CFGOnly = false) {
+ DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
+ CFGInfo.setHeatColors(ShowHeatColors);
+ CFGInfo.setEdgeWeights(ShowEdgeWeight);
+ CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
+
+ ViewGraph(&CFGInfo, "cfg." + F.getName(), CFGOnly);
}
namespace {
- struct CFGViewerLegacyPass : public FunctionPass {
- static char ID; // Pass identifcation, replacement for typeid
- CFGViewerLegacyPass() : FunctionPass(ID) {
- initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
- }
-
- bool runOnFunction(Function &F) override {
- auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
- auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
- viewCFG(F, BFI, BPI, /*isSimple=*/false);
- return false;
- }
+struct CFGViewerLegacyPass : public FunctionPass {
+ static char ID; // Pass identifcation, replacement for typeid
+ CFGViewerLegacyPass() : FunctionPass(ID) {
+ initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+ auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+ viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
+ return false;
+ }
- void print(raw_ostream &OS, const Module* = nullptr) const override {}
+ void print(raw_ostream &OS, const Module * = nullptr) const override {}
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- FunctionPass::getAnalysisUsage(AU); // Maybe Change to FunctionPass::...
- AU.addRequired<BlockFrequencyInfoWrapperPass>();
- AU.addRequired<BranchProbabilityInfoWrapperPass>();
- AU.setPreservesAll();
- }
- };
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ FunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<BlockFrequencyInfoWrapperPass>();
+ AU.addRequired<BranchProbabilityInfoWrapperPass>();
+ AU.setPreservesAll();
+ }
+};
}
char CFGViewerLegacyPass::ID = 0;
-INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
+INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false,
+ true)
-PreservedAnalyses CFGViewerPass::run(Function &F,
- FunctionAnalysisManager &AM) {
+PreservedAnalyses CFGViewerPass::run(Function &F, FunctionAnalysisManager &AM) {
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
- viewCFG(F, BFI, BPI, /*isSimple=*/false);
+ viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
return PreservedAnalyses::all();
}
-
namespace {
- struct CFGOnlyViewerLegacyPass : public FunctionPass {
- static char ID; // Pass identifcation, replacement for typeid
- CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
- initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
- }
-
- bool runOnFunction(Function &F) override {
- auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
- auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
- viewCFG(F, BFI, BPI, /*isSimple=*/false);
- return false;
- }
+struct CFGOnlyViewerLegacyPass : public FunctionPass {
+ static char ID; // Pass identifcation, replacement for typeid
+ CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
+ initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+ auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+ viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
+ return false;
+ }
- void print(raw_ostream &OS, const Module* = nullptr) const override {}
+ void print(raw_ostream &OS, const Module * = nullptr) const override {}
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- FunctionPass::getAnalysisUsage(AU);
- AU.addRequired<BlockFrequencyInfoWrapperPass>();
- AU.addRequired<BranchProbabilityInfoWrapperPass>();
- AU.setPreservesAll();
- }
- };
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ FunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<BlockFrequencyInfoWrapperPass>();
+ AU.addRequired<BranchProbabilityInfoWrapperPass>();
+ AU.setPreservesAll();
+ }
+};
}
char CFGOnlyViewerLegacyPass::ID = 0;
@@ -137,81 +157,81 @@ PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
FunctionAnalysisManager &AM) {
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
- viewCFG(F, BFI, BPI, /*isSimple=*/false);
+ viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
return PreservedAnalyses::all();
}
namespace {
- struct CFGPrinterLegacyPass : public FunctionPass {
- static char ID; // Pass identification, replacement for typeid
- CFGPrinterLegacyPass() : FunctionPass(ID) {
- initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
- }
-
- bool runOnFunction(Function &F) override {
- auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
- auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
- writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
- return false;
- }
+struct CFGPrinterLegacyPass : public FunctionPass {
+ static char ID; // Pass identification, replacement for typeid
+ CFGPrinterLegacyPass() : FunctionPass(ID) {
+ initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+ auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+ writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
+ return false;
+ }
- void print(raw_ostream &OS, const Module* = nullptr) const override {}
+ void print(raw_ostream &OS, const Module * = nullptr) const override {}
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- FunctionPass::getAnalysisUsage(AU);
- AU.addRequired<BlockFrequencyInfoWrapperPass>();
- AU.addRequired<BranchProbabilityInfoWrapperPass>();
- AU.setPreservesAll();
- }
- };
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ FunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<BlockFrequencyInfoWrapperPass>();
+ AU.addRequired<BranchProbabilityInfoWrapperPass>();
+ AU.setPreservesAll();
+ }
+};
}
char CFGPrinterLegacyPass::ID = 0;
-INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file",
- false, true)
+INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg",
+ "Print CFG of function to 'dot' file", false, true)
PreservedAnalyses CFGPrinterPass::run(Function &F,
FunctionAnalysisManager &AM) {
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
- writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
+ writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
return PreservedAnalyses::all();
}
namespace {
- struct CFGOnlyPrinterLegacyPass : public FunctionPass {
- static char ID; // Pass identification, replacement for typeid
- CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
- initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
- }
-
- bool runOnFunction(Function &F) override {
- auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
- auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
- writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
- return false;
- }
- void print(raw_ostream &OS, const Module* = nullptr) const override {}
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- FunctionPass::getAnalysisUsage(AU);
- AU.addRequired<BlockFrequencyInfoWrapperPass>();
- AU.addRequired<BranchProbabilityInfoWrapperPass>();
- AU.setPreservesAll();
- }
- };
+struct CFGOnlyPrinterLegacyPass : public FunctionPass {
+ static char ID; // Pass identification, replacement for typeid
+ CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
+ initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+ auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+ writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
+ return false;
+ }
+ void print(raw_ostream &OS, const Module * = nullptr) const override {}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ FunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<BlockFrequencyInfoWrapperPass>();
+ AU.addRequired<BranchProbabilityInfoWrapperPass>();
+ AU.setPreservesAll();
+ }
+};
}
char CFGOnlyPrinterLegacyPass::ID = 0;
INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
- "Print CFG of function to 'dot' file (with no function bodies)",
- false, true)
+ "Print CFG of function to 'dot' file (with no function bodies)",
+ false, true)
PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
FunctionAnalysisManager &AM) {
auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
- writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
+ writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
return PreservedAnalyses::all();
}
@@ -222,7 +242,7 @@ PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
///
void Function::viewCFG() const {
if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
- return;
+ return;
DOTFuncInfo CFGInfo(this);
ViewGraph(&CFGInfo, "cfg" + getName());
}
@@ -234,16 +254,16 @@ void Function::viewCFG() const {
///
void Function::viewCFGOnly() const {
if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
- return;
+ return;
DOTFuncInfo CFGInfo(this);
ViewGraph(&CFGInfo, "cfg" + getName(), true);
}
-FunctionPass *llvm::createCFGPrinterLegacyPassPass () {
+FunctionPass *llvm::createCFGPrinterLegacyPassPass() {
return new CFGPrinterLegacyPass();
}
-FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
+FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass() {
return new CFGOnlyPrinterLegacyPass();
}
@@ -252,8 +272,8 @@ void DOTGraphTraits<DOTFuncInfo *>::computeHiddenNodes(const Function *F) {
if (succ_begin(Node) == succ_end(Node)) {
const Instruction *TI = Node->getTerminator();
isHiddenBasicBlock[Node] =
- (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
- (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
+ (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
+ (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
return;
}
isHiddenBasicBlock[Node] = std::all_of(
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 8a658aa6adf7..dccd3d7f3f96 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -35,6 +35,7 @@ add_llvm_component_library(LLVMAnalysis
EHPersonalities.cpp
GlobalsModRef.cpp
GuardUtils.cpp
+ HeatUtils.cpp
IVDescriptors.cpp
IVUsers.cpp
IndirectCallPromotionAnalysis.cpp
diff --git a/llvm/lib/Analysis/HeatUtils.cpp b/llvm/lib/Analysis/HeatUtils.cpp
new file mode 100644
index 000000000000..aac4fe15068d
--- /dev/null
+++ b/llvm/lib/Analysis/HeatUtils.cpp
@@ -0,0 +1,64 @@
+//===-- HeatUtils.cpp - Utility for printing heat colors --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for printing heat colors based on heuristics or profiling
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/HeatUtils.h"
+#include "llvm/IR/Instructions.h"
+
+namespace llvm {
+
+static const unsigned heatSize = 100;
+static const std::string heatPalette[heatSize] = {
+ "#3d50c3", "#4055c8", "#4358cb", "#465ecf", "#4961d2", "#4c66d6", "#4f69d9",
+ "#536edd", "#5572df", "#5977e3", "#5b7ae5", "#5f7fe8", "#6282ea", "#6687ed",
+ "#6a8bef", "#6c8ff1", "#7093f3", "#7396f5", "#779af7", "#7a9df8", "#7ea1fa",
+ "#81a4fb", "#85a8fc", "#88abfd", "#8caffe", "#8fb1fe", "#93b5fe", "#96b7ff",
+ "#9abbff", "#9ebeff", "#a1c0ff", "#a5c3fe", "#a7c5fe", "#abc8fd", "#aec9fc",
+ "#b2ccfb", "#b5cdfa", "#b9d0f9", "#bbd1f8", "#bfd3f6", "#c1d4f4", "#c5d6f2",
+ "#c7d7f0", "#cbd8ee", "#cedaeb", "#d1dae9", "#d4dbe6", "#d6dce4", "#d9dce1",
+ "#dbdcde", "#dedcdb", "#e0dbd8", "#e3d9d3", "#e5d8d1", "#e8d6cc", "#ead5c9",
+ "#ecd3c5", "#eed0c0", "#efcebd", "#f1ccb8", "#f2cab5", "#f3c7b1", "#f4c5ad",
+ "#f5c1a9", "#f6bfa6", "#f7bca1", "#f7b99e", "#f7b599", "#f7b396", "#f7af91",
+ "#f7ac8e", "#f7a889", "#f6a385", "#f5a081", "#f59c7d", "#f4987a", "#f39475",
+ "#f29072", "#f08b6e", "#ef886b", "#ed8366", "#ec7f63", "#e97a5f", "#e8765c",
+ "#e57058", "#e36c55", "#e16751", "#de614d", "#dc5d4a", "#d85646", "#d65244",
+ "#d24b40", "#d0473d", "#cc403a", "#ca3b37", "#c53334", "#c32e31", "#be242e",
+ "#bb1b2c", "#b70d28"};
+
+uint64_t getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI) {
+ uint64_t maxFreq = 0;
+ for (const BasicBlock &BB : F) {
+ uint64_t freqVal = BFI->getBlockFreq(&BB).getFrequency();
+ if (freqVal >= maxFreq)
+ maxFreq = freqVal;
+ }
+ return maxFreq;
+}
+
+std::string getHeatColor(uint64_t freq, uint64_t maxFreq) {
+ if (freq > maxFreq)
+ freq = maxFreq;
+ double percent = log2(double(freq)) / log2(maxFreq);
+ return getHeatColor(percent);
+}
+
+std::string getHeatColor(double percent) {
+ if (percent > 1.0)
+ percent = 1.0;
+ if (percent < 0.0)
+ percent = 0.0;
+ unsigned colorId = unsigned(round(percent * (heatSize - 1.0)));
+ return heatPalette[colorId];
+}
+
+} // namespace llvm
\ No newline at end of file
diff --git a/llvm/test/Other/2007-06-05-PassID.ll b/llvm/test/Other/2007-06-05-PassID.ll
index 386e444caae1..6964f2824d68 100644
--- a/llvm/test/Other/2007-06-05-PassID.ll
+++ b/llvm/test/Other/2007-06-05-PassID.ll
@@ -1,5 +1,13 @@
;RUN: opt < %s -analyze -dot-cfg-only 2>/dev/null
;RUN: opt < %s -analyze -passes=dot-cfg-only 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg-only \
+;RUN: -cfg-heat-colors=true -cfg-weights=true 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg-only \
+;RUN: -cfg-heat-colors=false -cfg-weights=false 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg \
+;RUN: -cfg-heat-colors=true -cfg-weights=true 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg \
+;RUN: -cfg-heat-colors=false -cfg-weights=false 2>/dev/null
;PR 1497
define void @foo() {
diff --git a/llvm/test/Other/cfg-printer-branch-weights-percent.ll b/llvm/test/Other/cfg-printer-branch-weights-percent.ll
new file mode 100644
index 000000000000..bfbb73160444
--- /dev/null
+++ b/llvm/test/Other/cfg-printer-branch-weights-percent.ll
@@ -0,0 +1,19 @@
+;RUN: opt < %s -analyze -dot-cfg -cfg-weights -cfg-dot-filename-prefix=%t 2>/dev/null
+;RUN: FileCheck %s -input-file=%t.f.dot
+
+define void @f(i32) {
+entry:
+ %check = icmp sgt i32 %0, 0
+ br i1 %check, label %if, label %exit, !prof !0
+
+; CHECK: label="0.50%"
+; CHECK-NOT: ["];
+if: ; preds = %entry
+ br label %exit
+; CHECK: label="99.50%"
+; CHECK-NOT: ["];
+exit: ; preds = %entry, %if
+ ret void
+}
+
+!0 = !{!"branch_weights", i32 1, i32 200}
diff --git a/llvm/test/Other/cfg-printer-branch-weights.ll b/llvm/test/Other/cfg-printer-branch-weights.ll
index 200bc7d1fdde..a7a53c38653c 100644
--- a/llvm/test/Other/cfg-printer-branch-weights.ll
+++ b/llvm/test/Other/cfg-printer-branch-weights.ll
@@ -1,4 +1,4 @@
-;RUN: opt < %s -analyze -dot-cfg -cfg-dot-filename-prefix=%t 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg -cfg-weights -cfg-raw-weights -cfg-dot-filename-prefix=%t 2>/dev/null
;RUN: FileCheck %s -input-file=%t.f.dot
define void @f(i32) {
@@ -6,11 +6,11 @@ entry:
%check = icmp sgt i32 %0, 0
br i1 %check, label %if, label %exit, !prof !0
-; CHECK: label="W:1"
+; CHECK: label="W:7"
; CHECK-NOT: ["];
if: ; preds = %entry
br label %exit
-; CHECK: label="W:200"
+; CHECK: label="W:1600"
; CHECK-NOT: ["];
exit: ; preds = %entry, %if
ret void
diff --git a/llvm/test/Other/heat-colors-graphs.ll b/llvm/test/Other/heat-colors-graphs.ll
new file mode 100644
index 000000000000..1ec3601c7ff4
--- /dev/null
+++ b/llvm/test/Other/heat-colors-graphs.ll
@@ -0,0 +1,19 @@
+; RUN: opt < %s -analyze -dot-cfg -cfg-heat-colors -cfg-dot-filename-prefix=%t 2>/dev/null
+; RUN: FileCheck %s -input-file=%t.f.dot
+
+; CHECK: color="#{{[(a-z)(0-9)]+}}", style={{[a-z]+}}, fillcolor="#{{[(a-z)(0-9)]+}}"
+; CHECK: color="#{{[(a-z)(0-9)]+}}", style={{[a-z]+}}, fillcolor="#{{[(a-z)(0-9)]+}}"
+; CHECK: color="#{{[(a-z)(0-9)]+}}", style={{[a-z]+}}, fillcolor="#{{[(a-z)(0-9)]+}}"
+
+define void @f(i32) {
+entry:
+ %check = icmp sgt i32 %0, 0
+ br i1 %check, label %if, label %exit, !prof !0
+
+if: ; preds = %entry
+ br label %exit
+exit: ; preds = %entry, %if
+ ret void
+}
+
+!0 = !{!"branch_weights", i32 1, i32 200}
More information about the llvm-commits
mailing list