[BOLT] Print heatmap from perf2bolt (#139194)

Add perf2bolt `--heatmap` option to produce heatmaps during profile
aggregation.

Distinguish exclusive mode (`llvm-bolt-heatmap`) and optional mode 
(`perf2bolt --heatmap`), which impacts perf.data handling:
exclusive mode covers all addresses, whereas optional mode consumes
attached profile only covering function addresses.

Test Plan: updated per2bolt tests:
- pre-aggregated-perf.test: pre-aggregated data,
- bolt-address-translation-yaml.test: pre-aggregated + BOLTed input,
- perf_test.test: no-LBR perf data.
This commit is contained in:
Amir Ayupov
2025-05-13 13:23:18 -07:00
committed by GitHub
parent 7f4febde10
commit 0289ca09be
10 changed files with 73 additions and 41 deletions

View File

@@ -164,6 +164,10 @@ void DataAggregator::findPerfExecutable() {
void DataAggregator::start() {
outs() << "PERF2BOLT: Starting data aggregation job for " << Filename << "\n";
// Turn on heatmap building if requested by --heatmap flag.
if (!opts::HeatmapMode && opts::HeatmapOutput.getNumOccurrences())
opts::HeatmapMode = opts::HeatmapModeKind::HM_Optional;
// Don't launch perf for pre-aggregated files or when perf input is specified
// by the user.
if (opts::ReadPreAggregated || !opts::ReadPerfEvents.empty())
@@ -502,24 +506,25 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) {
errs() << "PERF2BOLT: failed to parse samples\n";
// Special handling for memory events
if (prepareToParse("mem events", MemEventsPPI, MemEventsErrorCallback))
return Error::success();
if (const std::error_code EC = parseMemEvents())
errs() << "PERF2BOLT: failed to parse memory events: " << EC.message()
<< '\n';
if (!prepareToParse("mem events", MemEventsPPI, MemEventsErrorCallback))
if (const std::error_code EC = parseMemEvents())
errs() << "PERF2BOLT: failed to parse memory events: " << EC.message()
<< '\n';
deleteTempFiles();
heatmap:
if (opts::HeatmapMode) {
if (std::error_code EC = printLBRHeatMap()) {
errs() << "ERROR: failed to print heat map: " << EC.message() << '\n';
exit(1);
}
exit(0);
}
return Error::success();
if (!opts::HeatmapMode)
return Error::success();
if (std::error_code EC = printLBRHeatMap())
return errorCodeToError(EC);
if (opts::HeatmapMode == opts::HeatmapModeKind::HM_Optional)
return Error::success();
assert(opts::HeatmapMode == opts::HeatmapModeKind::HM_Exclusive);
exit(0);
}
Error DataAggregator::readProfile(BinaryContext &BC) {
@@ -1351,15 +1356,14 @@ std::error_code DataAggregator::printLBRHeatMap() {
exit(1);
}
HM.print(opts::OutputFilename);
if (opts::OutputFilename == "-")
HM.printCDF(opts::OutputFilename);
else
HM.printCDF(opts::OutputFilename + ".csv");
if (opts::OutputFilename == "-")
HM.printSectionHotness(opts::OutputFilename);
else
HM.printSectionHotness(opts::OutputFilename + "-section-hotness.csv");
HM.print(opts::HeatmapOutput);
if (opts::HeatmapOutput == "-") {
HM.printCDF(opts::HeatmapOutput);
HM.printSectionHotness(opts::HeatmapOutput);
} else {
HM.printCDF(opts::HeatmapOutput + ".csv");
HM.printSectionHotness(opts::HeatmapOutput + "-section-hotness.csv");
}
return std::error_code();
}
@@ -1386,7 +1390,7 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
const uint64_t TraceTo = NextLBR->From;
const BinaryFunction *TraceBF =
getBinaryFunctionContainingAddress(TraceFrom);
if (opts::HeatmapMode) {
if (opts::HeatmapMode == opts::HeatmapModeKind::HM_Exclusive) {
FTInfo &Info = FallthroughLBRs[Trace(TraceFrom, TraceTo)];
++Info.InternCount;
} else if (TraceBF && TraceBF->containsAddress(TraceTo)) {
@@ -1424,7 +1428,7 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
NextLBR = &LBR;
// Record branches outside binary functions for heatmap.
if (opts::HeatmapMode) {
if (opts::HeatmapMode == opts::HeatmapModeKind::HM_Exclusive) {
TakenBranchInfo &Info = BranchLBRs[Trace(LBR.From, LBR.To)];
++Info.TakenCount;
continue;
@@ -1439,7 +1443,8 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
}
// Record LBR addresses not covered by fallthroughs (bottom-of-stack source
// and top-of-stack target) as basic samples for heatmap.
if (opts::HeatmapMode && !Sample.LBR.empty()) {
if (opts::HeatmapMode == opts::HeatmapModeKind::HM_Exclusive &&
!Sample.LBR.empty()) {
++BasicSamples[Sample.LBR.front().To];
++BasicSamples[Sample.LBR.back().From];
}