[llvm-branch-commits] [llvm] [BOLT] Parse branch type from perf script (PR #202813)
Amir Ayupov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jun 11 13:09:31 PDT 2026
https://github.com/aaupov updated https://github.com/llvm/llvm-project/pull/202813
>From 42df186d47af9dfe2b985b2a174163abe57da110 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Tue, 9 Jun 2026 16:36:50 -0700
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
=?UTF-8?q?itial=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 | 1 +
bolt/lib/Profile/DataAggregator.cpp | 28 ++++++++++++++++++----
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 1757d3aa56c65..8b432126f5ca0 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -88,6 +88,7 @@ class DataAggregator : public DataReader {
uint64_t From;
uint64_t To;
bool Mispred;
+ bool IsReturn;
};
friend raw_ostream &operator<<(raw_ostream &OS, const LBREntry &);
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index 0c879d1646b27..fbe9f316166f7 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -1292,7 +1292,10 @@ DataAggregator::getFallthroughsInTrace(BinaryFunction &BF, const Trace &Trace,
}
ErrorOr<DataAggregator::LBREntry> DataAggregator::parseLBREntry() {
+ /// perf script -F brstack entry format:
+ /// FROM/TO/EVENT/INTX/ABORT/CYCLES/TYPE/SPEC
LBREntry Res;
+ // From
ErrorOr<StringRef> FromStrRes = parseString('/');
if (std::error_code EC = FromStrRes.getError())
return EC;
@@ -1303,6 +1306,7 @@ ErrorOr<DataAggregator::LBREntry> DataAggregator::parseLBREntry() {
return make_error_code(llvm::errc::io_error);
}
+ // To
ErrorOr<StringRef> ToStrRes = parseString('/');
if (std::error_code EC = ToStrRes.getError())
return EC;
@@ -1313,10 +1317,11 @@ ErrorOr<DataAggregator::LBREntry> DataAggregator::parseLBREntry() {
return make_error_code(llvm::errc::io_error);
}
- ErrorOr<StringRef> MispredStrRes = parseString('/');
- if (std::error_code EC = MispredStrRes.getError())
+ // Event: M: mispredicted, P: predicted, N: not taken
+ ErrorOr<StringRef> EventStrRes = parseString('/');
+ if (std::error_code EC = EventStrRes.getError())
return EC;
- StringRef MispredStr = MispredStrRes.get();
+ StringRef MispredStr = EventStrRes.get();
// SPE brstack mispredicted flags might be up to two characters long:
// 'PN' or 'MN'. Where 'N' optionally appears.
bool ValidStrSize = opts::ArmSPE
@@ -1344,10 +1349,24 @@ 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
ErrorOr<StringRef> Rest = parseString(FieldSeparator, true);
if (std::error_code EC = Rest.getError())
return EC;
- if (Rest.get().size() < 5) {
+ if (Rest.get().size() < 3) {
reportError("expected rest of brstack entry");
Diag << "Found: " << Rest.get() << "\n";
return make_error_code(llvm::errc::io_error);
@@ -1789,6 +1808,7 @@ 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);
}
// Record LBR addresses not covered by fallthroughs (bottom-of-stack source
// and top-of-stack target) as basic samples for heatmap.
>From 111488ee225cc32ac9f785c68e333750d390b8b5 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Tue, 9 Jun 2026 21:33:06 -0700
Subject: [PATCH 2/2] return
Created using spr 1.3.8-beta.1
---
bolt/docs/profiles.md | 2 +-
bolt/include/bolt/Profile/DataAggregator.h | 15 ++++++++--
bolt/lib/Profile/DataAggregator.cpp | 32 ++++++++++------------
bolt/test/perf2bolt/perf_brstack.test | 2 +-
4 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/bolt/docs/profiles.md b/bolt/docs/profiles.md
index 4900c2fb008d0..d8cf7289b6115 100644
--- a/bolt/docs/profiles.md
+++ b/bolt/docs/profiles.md
@@ -62,7 +62,7 @@ without going through `perf.data`.
```
E <event>
S <start> <count>
-[TR] <branch> <ft_start> <ft_end> <count>
+[TR] <branch> <ft_start> <ft_end> <count> [<mispred_count>]
B <start> <end> <count> <mispred_count>
[Ff] <start> <end> <count>
r <start> <end> <count>
diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 8b432126f5ca0..3816904c8e8e6 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -143,6 +143,7 @@ class DataAggregator : public DataReader {
uint64_t TakenCount{0};
uint64_t MispredCount{0};
};
+ friend raw_ostream &operator<<(raw_ostream &OS, const TakenBranchInfo &TBI);
/// Intermediate storage for profile data. We save the results of parsing
/// and use them later for processing and assigning profile.
@@ -434,7 +435,7 @@ class DataAggregator : public DataReader {
/// File format syntax:
/// E <event>
/// S <start> <count>
- /// [TR] <start> <end> <ft_end> <count>
+ /// [TR] <start> <end> <ft_end> <count> [<mispred_count>]
/// B <start> <end> <count> <mispred_count>
/// [Ffr] <start> <end> <count>
///
@@ -473,6 +474,7 @@ class DataAggregator : public DataReader {
///
/// Trace profile combining branches and fall-throughs:
/// T 4b196f 4b19e0 4b19ef 2
+ /// T 4b196f 4b19e0 4b19ef 2 1
///
/// Legacy branch profile with separate branches and fall-throughs:
/// F 41be50 41be50 3
@@ -669,13 +671,20 @@ class DataAggregator : public DataReader {
inline raw_ostream &operator<<(raw_ostream &OS,
const DataAggregator::LBREntry &L) {
- OS << formatv("{0:x} -> {1:x}/{2}", L.From, L.To, L.Mispred ? 'M' : 'P');
+ OS << formatv("{0:x} -> {1:x}/{2}/{3}", L.From, L.To, L.Mispred ? 'M' : 'P',
+ L.IsReturn ? "RET" : "-");
return OS;
}
inline raw_ostream &operator<<(raw_ostream &OS,
const DataAggregator::Trace &T) {
- OS << formatv("T {0:x-} {1:x-} {2:x-}", T.Branch, T.From, T.To);
+ OS << formatv("{0:x-} {1:x-} {2:x-}", T.Branch, T.From, T.To);
+ return OS;
+}
+
+inline raw_ostream &operator<<(raw_ostream &OS,
+ const DataAggregator::TakenBranchInfo &TBI) {
+ OS << TBI.TakenCount << " " << TBI.MispredCount;
return OS;
}
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index fbe9f316166f7..2052b91dc342d 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -1366,7 +1366,7 @@ ErrorOr<DataAggregator::LBREntry> DataAggregator::parseLBREntry() {
ErrorOr<StringRef> Rest = parseString(FieldSeparator, true);
if (std::error_code EC = Rest.getError())
return EC;
- if (Rest.get().size() < 3) {
+ if (Rest.get().size() < 1) {
reportError("expected rest of brstack entry");
Diag << "Found: " << Rest.get() << "\n";
return make_error_code(llvm::errc::io_error);
@@ -1569,9 +1569,7 @@ std::error_code DataAggregator::parseAggregatedLBREntry() {
/// The number of fields to parse, set based on \p Type.
int AddrNum = 0;
- int CounterNum = 0;
/// Storage for parsed fields.
- StringRef EventName;
std::optional<Location> Addr[3];
int64_t Counters[2] = {0};
@@ -1586,8 +1584,8 @@ std::error_code DataAggregator::parseAggregatedLBREntry() {
StringRef Str = StrOrErr.get();
if (Type == EVENT_NAME) {
- EventName = Str;
- break;
+ EventNames.insert(Str);
+ return std::error_code();
}
Type = StringSwitch<AggregatedLBREntry>(Str)
@@ -1607,9 +1605,7 @@ std::error_code DataAggregator::parseAggregatedLBREntry() {
}
using SSI = StringSwitch<int>;
- AddrNum =
- SSI(Str).Cases({"T", "R"}, 3).Case("S", 1).Case("E", 0).Default(2);
- CounterNum = SSI(Str).Case("B", 2).Case("E", 0).Default(1);
+ AddrNum = SSI(Str).Cases({"T", "R"}, 3).Case("S", 1).Default(2);
}
/// Parse locations depending on entry type, recording them in \p Addr array.
@@ -1628,6 +1624,10 @@ std::error_code DataAggregator::parseAggregatedLBREntry() {
}
/// Parse counters depending on entry type.
+ const bool HasMispreds =
+ (Type == BRANCH || Type == TRACE || Type == RETURN) &&
+ ParsingBuf.split('\n').first.contains(FieldSeparator);
+ const int CounterNum = 1 + HasMispreds;
for (int I = 0; I < CounterNum; ++I) {
while (checkAndConsumeFS()) {
}
@@ -1648,12 +1648,6 @@ std::error_code DataAggregator::parseAggregatedLBREntry() {
int64_t Mispreds = Counters[1];
switch (Type) {
- /// Record event name into \p EventNames and return.
- case EVENT_NAME: {
- EventNames.insert(EventName);
- return std::error_code();
- }
-
/// Record basic IP sample into \p BasicSamples and return.
case SAMPLE: {
const uint64_t FromOffset = Addr[0]->Offset;
@@ -2486,9 +2480,13 @@ DataAggregator::writePreAggregatedFile(StringRef OutputFilename) const {
if (EC)
return EC;
- for (const auto &[Trace, Info] : Traces)
- OS << Trace << " " << Info.TakenCount << '\n';
- OS << formatv("E {0:$[,]}\n", EventNames.keys());
+ for (const auto &[Trace, Info] : Traces) {
+ auto ReturnIt = Returns.find(Trace.Branch);
+ const bool IsRet = ReturnIt != Returns.end() && ReturnIt->second;
+ OS << (IsRet ? 'R' : 'T') << " " << Trace << " " << Info << '\n';
+ }
+ if (!EventNames.empty())
+ OS << formatv("E {0:$[,]}\n", EventNames.keys());
for (const auto &[PC, Count] : BasicSamples)
OS << formatv("S {0:x-} {1}\n", PC, Count);
diff --git a/bolt/test/perf2bolt/perf_brstack.test b/bolt/test/perf2bolt/perf_brstack.test
index e93f440650006..d7fe6abebebc6 100644
--- a/bolt/test/perf2bolt/perf_brstack.test
+++ b/bolt/test/perf2bolt/perf_brstack.test
@@ -3,7 +3,7 @@
REQUIRES: system-linux, perf-brstack
RUN: %clang %S/Inputs/perf_test.c -no-pie -fuse-ld=lld -o %t
-RUN: perf record -Fmax -j any,u -e cycles:u -o %t.perf.data -- %t
+RUN: perf record -Fmax -j any,u,save_type -e cycles:u -o %t.perf.data -- %t
RUN: perf2bolt %t -p=%t.perf.data -o %t.fdata -ignore-build-id
RUN: perf2bolt %t -p=%t.perf.data -o %t.preagg -ignore-build-id --profile-format=preagg
RUN: perf2bolt %t -pa -p=%t.preagg -o %t.roundtrip.fdata -ignore-build-id
More information about the llvm-branch-commits
mailing list