Skip to content

Commit 8b67853

Browse files
author
Kirill Naumov
committed
[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
1 parent 878d960 commit 8b67853

File tree

9 files changed

+385
-150
lines changed

9 files changed

+385
-150
lines changed

llvm/include/llvm/Analysis/CFGPrinter.h

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "llvm/Analysis/BlockFrequencyInfo.h"
2222
#include "llvm/Analysis/BranchProbabilityInfo.h"
23+
#include "llvm/Analysis/HeatUtils.h"
2324
#include "llvm/IR/CFG.h"
2425
#include "llvm/IR/Constants.h"
2526
#include "llvm/IR/Function.h"
@@ -29,26 +30,22 @@
2930
#include "llvm/Support/GraphWriter.h"
3031

3132
namespace llvm {
32-
class CFGViewerPass
33-
: public PassInfoMixin<CFGViewerPass> {
33+
class CFGViewerPass : public PassInfoMixin<CFGViewerPass> {
3434
public:
3535
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
3636
};
3737

38-
class CFGOnlyViewerPass
39-
: public PassInfoMixin<CFGOnlyViewerPass> {
38+
class CFGOnlyViewerPass : public PassInfoMixin<CFGOnlyViewerPass> {
4039
public:
4140
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
4241
};
4342

44-
class CFGPrinterPass
45-
: public PassInfoMixin<CFGPrinterPass> {
43+
class CFGPrinterPass : public PassInfoMixin<CFGPrinterPass> {
4644
public:
4745
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
4846
};
4947

50-
class CFGOnlyPrinterPass
51-
: public PassInfoMixin<CFGOnlyPrinterPass> {
48+
class CFGOnlyPrinterPass : public PassInfoMixin<CFGOnlyPrinterPass> {
5249
public:
5350
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
5451
};
@@ -58,20 +55,45 @@ class DOTFuncInfo {
5855
const Function *F;
5956
const BlockFrequencyInfo *BFI;
6057
const BranchProbabilityInfo *BPI;
58+
uint64_t MaxFreq;
59+
bool ShowHeat;
60+
bool EdgeWeights;
61+
bool RawWeights;
6162

6263
public:
63-
DOTFuncInfo(const Function *F) : DOTFuncInfo(F, nullptr, nullptr) {}
64+
DOTFuncInfo(const Function *F) : DOTFuncInfo(F, nullptr, nullptr, 0) {}
6465

6566
DOTFuncInfo(const Function *F, const BlockFrequencyInfo *BFI,
66-
BranchProbabilityInfo *BPI)
67-
: F(F), BFI(BFI), BPI(BPI) {
67+
BranchProbabilityInfo *BPI, uint64_t MaxFreq)
68+
: F(F), BFI(BFI), BPI(BPI), MaxFreq(MaxFreq) {
69+
ShowHeat = false;
70+
EdgeWeights = true;
71+
RawWeights = true;
6872
}
6973

7074
const BlockFrequencyInfo *getBFI() { return BFI; }
7175

7276
const BranchProbabilityInfo *getBPI() { return BPI; }
7377

7478
const Function *getFunction() { return this->F; }
79+
80+
uint64_t getMaxFreq() { return MaxFreq; }
81+
82+
uint64_t getFreq(const BasicBlock *BB) {
83+
return BFI->getBlockFreq(BB).getFrequency();
84+
}
85+
86+
void setHeatColors(bool ShowHeat) { this->ShowHeat = ShowHeat; }
87+
88+
bool showHeatColors() { return ShowHeat; }
89+
90+
void setRawEdgeWeights(bool RawWeights) { this->RawWeights = RawWeights; }
91+
92+
bool useRawEdgeWeights() { return RawWeights; }
93+
94+
void setEdgeWeights(bool EdgeWeights) { this->EdgeWeights = EdgeWeights; }
95+
96+
bool showEdgeWeights() { return EdgeWeights; }
7597
};
7698

7799
template <>
@@ -96,12 +118,13 @@ struct GraphTraits<DOTFuncInfo *> : public GraphTraits<const BasicBlock *> {
96118
}
97119
};
98120

99-
template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
121+
template <>
122+
struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
100123

101124
// Cache for is hidden property
102-
llvm::DenseMap <const BasicBlock *, bool> isHiddenBasicBlock;
125+
llvm::DenseMap<const BasicBlock *, bool> isHiddenBasicBlock;
103126

104-
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
127+
DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
105128

106129
static std::string getGraphName(DOTFuncInfo *CFGInfo) {
107130
return "CFG for '" + CFGInfo->getFunction()->getName().str() + "' function";
@@ -131,40 +154,39 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
131154

132155
OS << *Node;
133156
std::string OutStr = OS.str();
134-
if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
157+
if (OutStr[0] == '\n')
158+
OutStr.erase(OutStr.begin());
135159

136160
// Process string output to make it nicer...
137161
unsigned ColNum = 0;
138162
unsigned LastSpace = 0;
139163
for (unsigned i = 0; i != OutStr.length(); ++i) {
140-
if (OutStr[i] == '\n') { // Left justify
164+
if (OutStr[i] == '\n') { // Left justify
141165
OutStr[i] = '\\';
142-
OutStr.insert(OutStr.begin()+i+1, 'l');
166+
OutStr.insert(OutStr.begin() + i + 1, 'l');
143167
ColNum = 0;
144168
LastSpace = 0;
145-
} else if (OutStr[i] == ';') { // Delete comments!
146-
unsigned Idx = OutStr.find('\n', i+1); // Find end of line
147-
OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx);
169+
} else if (OutStr[i] == ';') { // Delete comments!
170+
unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
171+
OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
148172
--i;
149-
} else if (ColNum == MaxColumns) { // Wrap lines.
173+
} else if (ColNum == MaxColumns) { // Wrap lines.
150174
// Wrap very long names even though we can't find a space.
151175
if (!LastSpace)
152176
LastSpace = i;
153177
OutStr.insert(LastSpace, "\\l...");
154178
ColNum = i - LastSpace;
155179
LastSpace = 0;
156180
i += 3; // The loop will advance 'i' again.
157-
}
158-
else
181+
} else
159182
++ColNum;
160183
if (OutStr[i] == ' ')
161184
LastSpace = i;
162185
}
163186
return OutStr;
164187
}
165188

166-
std::string getNodeLabel(const BasicBlock *Node,
167-
DOTFuncInfo *CFGInfo) {
189+
std::string getNodeLabel(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
168190

169191
if (isSimple())
170192
return getSimpleNodeLabel(Node, CFGInfo);
@@ -183,7 +205,8 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
183205
if (const SwitchInst *SI = dyn_cast<SwitchInst>(Node->getTerminator())) {
184206
unsigned SuccNo = I.getSuccessorIndex();
185207

186-
if (SuccNo == 0) return "def";
208+
if (SuccNo == 0)
209+
return "def";
187210

188211
std::string Str;
189212
raw_string_ostream OS(Str);
@@ -197,37 +220,80 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
197220
/// Display the raw branch weights from PGO.
198221
std::string getEdgeAttributes(const BasicBlock *Node, const_succ_iterator I,
199222
DOTFuncInfo *CFGInfo) {
223+
if (!CFGInfo->showEdgeWeights())
224+
return "";
225+
200226
const Instruction *TI = Node->getTerminator();
201227
if (TI->getNumSuccessors() == 1)
228+
return "penwidth=2";
229+
230+
unsigned OpNo = I.getSuccessorIndex();
231+
232+
if (OpNo >= TI->getNumSuccessors())
202233
return "";
234+
235+
BasicBlock *SuccBB = TI->getSuccessor(OpNo);
236+
auto BranchProb = CFGInfo->getBPI()->getEdgeProbability(Node, SuccBB);
237+
double WeightPercent = ((double)BranchProb.getNumerator()) /
238+
((double)BranchProb.getDenominator());
239+
double Width = 1 + WeightPercent;
240+
241+
if (!CFGInfo->useRawEdgeWeights())
242+
return formatv("label=\"{0:P}\" penwidth={1}", WeightPercent, Width)
243+
.str();
244+
245+
// Prepend a 'W' to indicate that this is a weight rather than the actual
246+
// profile count (due to scaling).
247+
248+
uint64_t Freq = CFGInfo->getFreq(Node);
249+
std::string Attrs = formatv("label=\"W:{0}\" penwidth={1}",
250+
(uint64_t)(Freq * WeightPercent), Width);
251+
if (Attrs.size())
252+
return Attrs;
253+
203254
MDNode *WeightsNode = TI->getMetadata(LLVMContext::MD_prof);
204255
if (!WeightsNode)
205256
return "";
206257

207258
MDString *MDName = cast<MDString>(WeightsNode->getOperand(0));
208259
if (MDName->getString() != "branch_weights")
209260
return "";
210-
unsigned OpNo = I.getSuccessorIndex() + 1;
261+
262+
OpNo = I.getSuccessorIndex() + 1;
211263
if (OpNo >= WeightsNode->getNumOperands())
212264
return "";
213265
ConstantInt *Weight =
214266
mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(OpNo));
215267
if (!Weight)
216268
return "";
269+
return ("label=\"W:" + std::to_string(Weight->getZExtValue()) +
270+
"\" penwidth=" + std::to_string(Width));
271+
}
217272

218-
// Prepend a 'W' to indicate that this is a weight rather than the actual
219-
// profile count (due to scaling).
220-
return ("label=\"W:" + Twine(Weight->getZExtValue()) + "\"").str();
273+
std::string getNodeAttributes(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
274+
275+
if (!CFGInfo->showHeatColors())
276+
return "";
277+
278+
uint64_t Freq = CFGInfo->getFreq(Node);
279+
std::string Color = getHeatColor(Freq, CFGInfo->getMaxFreq());
280+
std::string EdgeColor = (Freq <= (CFGInfo->getMaxFreq() / 2))
281+
? (getHeatColor(0))
282+
: (getHeatColor(1));
283+
284+
std::string Attrs = "color=\"" + EdgeColor + "ff\", style=filled," +
285+
" fillcolor=\"" + Color + "70\"";
286+
return Attrs;
221287
}
222288
bool isNodeHidden(const BasicBlock *Node);
223289
void computeHiddenNodes(const Function *F);
224290
};
225291
} // End llvm namespace
226292

227293
namespace llvm {
228-
class FunctionPass;
229-
FunctionPass *createCFGPrinterLegacyPassPass ();
230-
FunctionPass *createCFGOnlyPrinterLegacyPassPass ();
294+
class FunctionPass;
295+
FunctionPass *createCFGPrinterLegacyPassPass();
296+
FunctionPass *createCFGOnlyPrinterLegacyPassPass();
231297
} // End llvm namespace
232298

233299
#endif
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===-- HeatUtils.h - Utility for printing heat colors ----------*- C++ -*-===//
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+
// Utility for printing heat colors based on profiling information.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_ANALYSIS_HEATUTILS_H
15+
#define LLVM_ANALYSIS_HEATUTILS_H
16+
17+
#include "llvm/Analysis/BlockFrequencyInfo.h"
18+
#include "llvm/IR/BasicBlock.h"
19+
#include "llvm/IR/CallSite.h"
20+
#include "llvm/IR/Function.h"
21+
#include "llvm/IR/Module.h"
22+
23+
#include <string>
24+
25+
namespace llvm {
26+
27+
// Returns the maximum frequency of a BB in a function.
28+
uint64_t getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI);
29+
30+
// Calculates heat color based on current and maximum frequencies.
31+
std::string getHeatColor(uint64_t freq, uint64_t maxFreq);
32+
33+
// Calculates heat color based on percent of "hotness".
34+
std::string getHeatColor(double percent);
35+
36+
} // namespace llvm
37+
38+
#endif

0 commit comments

Comments
 (0)