Skip to content

Commit 733dc3e

Browse files
committed
[BOLT] Report per-section hotness in bolt-heatmap.
This patch adds a new feature to bolt heatmap to print the hotness of each section in terms of the percentage of samples within that section. Sample output generated for the clang binary: Section Name, Begin Address, End Address, Percentage Hotness .text, 0x1a7b9b0, 0x20a2cc0, 1.4709 .init, 0x20a2cc0, 0x20a2ce1, 0.0001 .fini, 0x20a2ce4, 0x20a2cf2, 0.0000 .text.unlikely, 0x20a2d00, 0x431990c, 0.3061 .text.hot, 0x4319910, 0x4bc6927, 97.2197 .text.startup, 0x4bc6930, 0x4c10c89, 0.0058 .plt, 0x4c10c90, 0x4c12010, 0.9974 Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D124412
1 parent f6dff93 commit 733dc3e

File tree

3 files changed

+100
-4
lines changed

3 files changed

+100
-4
lines changed

bolt/include/bolt/Profile/Heatmap.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@
1212
#include "llvm/ADT/StringRef.h"
1313
#include <cstdint>
1414
#include <map>
15+
#include <vector>
1516

1617
namespace llvm {
1718
class raw_ostream;
1819

1920
namespace bolt {
2021

22+
/// Struct representing a section name and its address range in the binary.
23+
struct SectionNameAndRange {
24+
StringRef Name;
25+
uint64_t BeginAddress;
26+
uint64_t EndAddress;
27+
};
28+
2129
class Heatmap {
2230
/// Number of bytes per entry in the heat map.
2331
size_t BucketSize;
@@ -34,11 +42,15 @@ class Heatmap {
3442
/// Map buckets to the number of samples.
3543
std::map<uint64_t, uint64_t> Map;
3644

45+
/// Map section names to their address range.
46+
const std::vector<SectionNameAndRange> TextSections;
47+
3748
public:
3849
explicit Heatmap(uint64_t BucketSize = 4096, uint64_t MinAddress = 0,
39-
uint64_t MaxAddress = std::numeric_limits<uint64_t>::max())
40-
: BucketSize(BucketSize), MinAddress(MinAddress),
41-
MaxAddress(MaxAddress){};
50+
uint64_t MaxAddress = std::numeric_limits<uint64_t>::max(),
51+
std::vector<SectionNameAndRange> TextSections = {})
52+
: BucketSize(BucketSize), MinAddress(MinAddress), MaxAddress(MaxAddress),
53+
TextSections(TextSections) {}
4254

4355
inline bool ignoreAddress(uint64_t Address) const {
4456
return (Address > MaxAddress) || (Address < MinAddress);
@@ -65,6 +77,10 @@ class Heatmap {
6577

6678
void printCDF(raw_ostream &OS) const;
6779

80+
void printSectionHotness(StringRef Filename) const;
81+
82+
void printSectionHotness(raw_ostream &OS) const;
83+
6884
size_t size() const { return Map.size(); }
6985
};
7086

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,22 @@ namespace {
116116
const char TimerGroupName[] = "aggregator";
117117
const char TimerGroupDesc[] = "Aggregator";
118118

119+
std::vector<SectionNameAndRange> getTextSections(const BinaryContext *BC) {
120+
std::vector<SectionNameAndRange> sections;
121+
for (BinarySection &Section : BC->sections()) {
122+
if (!Section.isText())
123+
continue;
124+
if (Section.getSize() == 0)
125+
continue;
126+
sections.push_back(
127+
{Section.getName(), Section.getAddress(), Section.getEndAddress()});
128+
}
129+
std::sort(sections.begin(), sections.end(),
130+
[](const SectionNameAndRange &A, const SectionNameAndRange &B) {
131+
return A.BeginAddress < B.BeginAddress;
132+
});
133+
return sections;
134+
}
119135
}
120136

121137
constexpr uint64_t DataAggregator::KernelBaseAddr;
@@ -1292,7 +1308,7 @@ std::error_code DataAggregator::printLBRHeatMap() {
12921308
opts::HeatmapMinAddress = KernelBaseAddr;
12931309
}
12941310
Heatmap HM(opts::HeatmapBlock, opts::HeatmapMinAddress,
1295-
opts::HeatmapMaxAddress);
1311+
opts::HeatmapMaxAddress, getTextSections(BC));
12961312
uint64_t NumTotalSamples = 0;
12971313

12981314
if (opts::BasicAggregation) {
@@ -1374,6 +1390,10 @@ std::error_code DataAggregator::printLBRHeatMap() {
13741390
HM.printCDF(opts::OutputFilename);
13751391
else
13761392
HM.printCDF(opts::OutputFilename + ".csv");
1393+
if (opts::OutputFilename == "-")
1394+
HM.printSectionHotness(opts::OutputFilename);
1395+
else
1396+
HM.printSectionHotness(opts::OutputFilename + "-section-hotness.csv");
13771397

13781398
return std::error_code();
13791399
}

bolt/lib/Profile/Heatmap.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "bolt/Profile/Heatmap.h"
1010
#include "bolt/Utils/CommandLineOpts.h"
11+
#include "llvm/ADT/StringMap.h"
1112
#include "llvm/ADT/Twine.h"
1213
#include "llvm/Support/CommandLine.h"
1314
#include "llvm/Support/Debug.h"
@@ -251,5 +252,64 @@ void Heatmap::printCDF(raw_ostream &OS) const {
251252
Counts.clear();
252253
}
253254

255+
void Heatmap::printSectionHotness(StringRef FileName) const {
256+
std::error_code EC;
257+
raw_fd_ostream OS(FileName, EC, sys::fs::OpenFlags::OF_None);
258+
if (EC) {
259+
errs() << "error opening output file: " << EC.message() << '\n';
260+
exit(1);
261+
}
262+
printSectionHotness(OS);
263+
}
264+
265+
void Heatmap::printSectionHotness(raw_ostream &OS) const {
266+
uint64_t NumTotalCounts = 0;
267+
StringMap<uint64_t> SectionHotness;
268+
unsigned TextSectionIndex = 0;
269+
270+
if (TextSections.empty())
271+
return;
272+
273+
uint64_t UnmappedHotness = 0;
274+
auto RecordUnmappedBucket = [&](uint64_t Address, uint64_t Frequency) {
275+
errs() << "Couldn't map the address bucket [0x" << Twine::utohexstr(Address)
276+
<< ", 0x" << Twine::utohexstr(Address + BucketSize)
277+
<< "] containing " << Frequency
278+
<< " samples to a text section in the binary.";
279+
UnmappedHotness += Frequency;
280+
};
281+
282+
for (const std::pair<const uint64_t, uint64_t> &KV : Map) {
283+
NumTotalCounts += KV.second;
284+
// We map an address bucket to the first section (lowest address)
285+
// overlapping with that bucket.
286+
auto Address = KV.first * BucketSize;
287+
while (TextSectionIndex < TextSections.size() &&
288+
Address >= TextSections[TextSectionIndex].EndAddress)
289+
TextSectionIndex++;
290+
if (TextSectionIndex >= TextSections.size() ||
291+
Address + BucketSize < TextSections[TextSectionIndex].BeginAddress) {
292+
RecordUnmappedBucket(Address, KV.second);
293+
continue;
294+
}
295+
SectionHotness[TextSections[TextSectionIndex].Name] += KV.second;
296+
}
297+
298+
assert(NumTotalCounts > 0 &&
299+
"total number of heatmap buckets should be greater than 0");
300+
301+
OS << "Section Name, Begin Address, End Address, Percentage Hotness\n";
302+
for (auto &TextSection : TextSections) {
303+
OS << TextSection.Name << ", 0x"
304+
<< Twine::utohexstr(TextSection.BeginAddress) << ", 0x"
305+
<< Twine::utohexstr(TextSection.EndAddress) << ", "
306+
<< format("%.4f",
307+
100.0 * SectionHotness[TextSection.Name] / NumTotalCounts)
308+
<< "\n";
309+
}
310+
if (UnmappedHotness > 0)
311+
OS << "[unmapped], 0x0, 0x0, "
312+
<< format("%.4f", 100.0 * UnmappedHotness / NumTotalCounts) << "\n";
313+
}
254314
} // namespace bolt
255315
} // namespace llvm

0 commit comments

Comments
 (0)