[llvm] [BOLT] Fix perf return identification (PR #203609)
Amir Ayupov via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 12 11:55:25 PDT 2026
https://github.com/aaupov created https://github.com/llvm/llvm-project/pull/203609
If perf data doesn't have branch type recorded, missing value would
incorrectly be interpreted as "not-a-return".
Only populate Returns map if the branch type is available.
Fixes bug introduced in #202813.
Introduce `--parse-branch-type` (default on) currently used for testing.
Test Plan: updated perf_brstack.test
>From 19c1150d3c781be35cd8d65d7452026f04d001b9 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Fri, 12 Jun 2026 11:55:13 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
=?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.8-beta.1
---
bolt/include/bolt/Profile/DataAggregator.h | 8 ++---
bolt/lib/Profile/DataAggregator.cpp | 37 +++++++++++-----------
bolt/test/perf2bolt/perf_brstack.test | 9 ++++++
3 files changed, 32 insertions(+), 22 deletions(-)
diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index fde7187973edd..31ae8cfa53ee9 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -90,10 +90,10 @@ class DataAggregator : public DataReader {
private:
struct LBREntry {
- uint64_t From;
- uint64_t To;
- bool Mispred;
- bool IsReturn;
+ uint64_t From{0};
+ uint64_t To{0};
+ bool Mispred{false};
+ bool IsReturn{false};
};
friend raw_ostream &operator<<(raw_ostream &OS, const LBREntry &);
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index 19bb63e88bdae..71f3cb66c3818 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -84,6 +84,11 @@ static cl::opt<bool> ParseMemProfile(
"on by default unless `--itrace` is set."),
cl::init(true), cl::cat(AggregatorCategory));
+static cl::opt<bool>
+ ParseBranchType("parse-branch-type",
+ cl::desc("enable perf branch type parsing"), cl::init(true),
+ cl::cat(AggregatorCategory));
+
static cl::opt<unsigned long long>
FilterPID("pid",
cl::desc("only use samples from process with specified PID"),
@@ -1371,24 +1376,20 @@ ErrorOr<DataAggregator::LBREntry> DataAggregator::parseLBREntry() {
MispredWarning = false;
}
- // Transaction, abort, cycles
- for (unsigned I = 0; I < 3; ++I) {
- ErrorOr<StringRef> IgnoredStr = parseString('/');
- if (std::error_code EC = IgnoredStr.getError())
- return EC;
- }
-
- // Type: COND/UNCOND/IND/CALL/IND_CALL/RET
- ErrorOr<StringRef> TypeStr = parseString('/');
- if (std::error_code EC = TypeStr.getError())
- return EC;
- Res.IsReturn = TypeStr.get() == "RET";
-
- // Branch speculation
+ // Rest of the entry:
+ // INTX/ABORT/CYCLES/TYPE/SPEC
ErrorOr<StringRef> Rest = parseString(FieldSeparator, true);
if (std::error_code EC = Rest.getError())
return EC;
- if (Rest.get().size() < 1) {
+
+ bool ValidRest = Rest.get().size() >= 5;
+ if (opts::ParseBranchType) {
+ SmallVector<StringRef, 5> RestFields;
+ Rest.get().split(RestFields, '/');
+ ValidRest = RestFields.size() >= 5 && !RestFields[4].empty();
+ Res.IsReturn = ValidRest && RestFields[3] == "RET";
+ }
+ if (!ValidRest) {
reportError("expected rest of brstack entry");
Diag << "Found: " << Rest.get() << "\n";
return make_error_code(llvm::errc::io_error);
@@ -1832,7 +1833,8 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
TakenBranchInfo &Info = TraceMap[Trace{LBR.From, LBR.To, TraceTo}];
++Info.TakenCount;
Info.MispredCount += LBR.Mispred;
- Returns.emplace(LBR.From, LBR.IsReturn);
+ if (LBR.IsReturn)
+ Returns.emplace(LBR.From, true);
}
// Record LBR addresses not covered by fallthroughs (bottom-of-stack source
// and top-of-stack target) as basic samples for heatmap.
@@ -2517,8 +2519,7 @@ DataAggregator::writePreAggregatedFile(StringRef OutputFilename) const {
return EC;
for (const auto &[Trace, Info] : Traces) {
- auto ReturnIt = Returns.find(Trace.Branch);
- const bool IsRet = ReturnIt != Returns.end() && ReturnIt->second;
+ const bool IsRet = Returns.count(Trace.Branch);
OS << (IsRet ? 'R' : 'T') << " " << Trace << " " << Info << '\n';
}
if (!EventNames.empty())
diff --git a/bolt/test/perf2bolt/perf_brstack.test b/bolt/test/perf2bolt/perf_brstack.test
index d7fe6abebebc6..af19df0989adf 100644
--- a/bolt/test/perf2bolt/perf_brstack.test
+++ b/bolt/test/perf2bolt/perf_brstack.test
@@ -10,3 +10,12 @@ RUN: perf2bolt %t -pa -p=%t.preagg -o %t.roundtrip.fdata -ignore-build-id
RUN: sort %t.fdata > %t.fdata.sorted
RUN: sort %t.roundtrip.fdata > %t.roundtrip.fdata.sorted
RUN: diff %t.fdata.sorted %t.roundtrip.fdata.sorted
+## Check branch type (return) parsing: pre-aggregated profile is dumped before
+## Returns map is populated from disassembly, so we can use it to check if there
+## are/aren't any pre-aggregated returns.
+RUN: perf record -Fmax -j any,u -e cycles:u -o %t.perf.data.notype -- %t
+RUN: perf2bolt %t -p=%t.perf.data.notype -o %t.preagg.notype -ignore-build-id \
+RUN: --profile-format=preagg --parse-branch-type=false
+## Expect no returns without branch type
+RUN: FileCheck %s --input-file=%t.preagg.notype --check-prefix=CHECK-NOTYPE
+CHECK-NOTYPE-NOT: R
More information about the llvm-commits
mailing list