[llvm] [BOLT] Make mispreds optional for preaggregated B/T/R (PR #202856)
Amir Ayupov via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 22:18:54 PDT 2026
https://github.com/aaupov created https://github.com/llvm/llvm-project/pull/202856
Extend the format with an optional mispredictions field.
Update parsing and pre-aggregated profile writer.
Test Plan:
added PreAggregatedX86TestHelper.OptionalMispredField
updated pre-aggregated-records.s
>From fd5073e7bb0378bcc25f176911e63aca45536159 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Tue, 9 Jun 2026 22:18:42 -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/docs/profiles.md | 4 ++--
bolt/include/bolt/Profile/DataAggregator.h | 13 +++++++++--
bolt/lib/Profile/DataAggregator.cpp | 9 +++++---
bolt/test/X86/pre-aggregated-records.s | 17 +++++++++-----
bolt/unittests/Profile/DataAggregator.cpp | 27 ++++++++++++++++++++++
5 files changed, 57 insertions(+), 13 deletions(-)
diff --git a/bolt/docs/profiles.md b/bolt/docs/profiles.md
index 4900c2fb008d0..7eeb13b3d5215 100644
--- a/bolt/docs/profiles.md
+++ b/bolt/docs/profiles.md
@@ -62,8 +62,8 @@ without going through `perf.data`.
```
E <event>
S <start> <count>
-[TR] <branch> <ft_start> <ft_end> <count>
-B <start> <end> <count> <mispred_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 1757d3aa56c65..6fb25529561f8 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -142,6 +142,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.
@@ -433,8 +434,8 @@ class DataAggregator : public DataReader {
/// File format syntax:
/// E <event>
/// S <start> <count>
- /// [TR] <start> <end> <ft_end> <count>
- /// B <start> <end> <count> <mispred_count>
+ /// [TR] <start> <end> <ft_end> <count> [<mispred_count>]
+ /// B <start> <end> <count> [<mispred_count>]
/// [Ffr] <start> <end> <count>
///
/// where <start>, <end>, <ft_end> have the format [<id>:]<offset>
@@ -472,12 +473,14 @@ 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
/// F 41be90 41be90 4
/// B 4b1942 39b57f0 3 0
/// B 4b196f 4b19e0 2 0
+ /// B 4b196f 4b19e0 2
void parsePreAggregated();
/// Parse the full output of pre-aggregated LBR samples generated by
@@ -678,6 +681,12 @@ inline raw_ostream &operator<<(raw_ostream &OS,
return OS;
}
+inline raw_ostream &operator<<(raw_ostream &OS,
+ const DataAggregator::TakenBranchInfo &TBI) {
+ OS << TBI.TakenCount << " " << TBI.MispredCount;
+ return OS;
+}
+
inline raw_ostream &operator<<(raw_ostream &OS,
const DataAggregator::PerfProcessType &T) {
OS << DataAggregator::PerfProcessInfo::PerfProcessTypeNames[T];
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index 0c879d1646b27..761edcc951f4c 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -1590,7 +1590,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);
+ CounterNum = Str != "E";
}
/// Parse locations depending on entry type, recording them in \p Addr array.
@@ -1609,6 +1609,8 @@ std::error_code DataAggregator::parseAggregatedLBREntry() {
}
/// Parse counters depending on entry type.
+ if (Type == BRANCH || Type == TRACE || Type == RETURN)
+ CounterNum += ParsingBuf.split('\n').first.contains(FieldSeparator);
for (int I = 0; I < CounterNum; ++I) {
while (checkAndConsumeFS()) {
}
@@ -2467,8 +2469,9 @@ DataAggregator::writePreAggregatedFile(StringRef OutputFilename) const {
return EC;
for (const auto &[Trace, Info] : Traces)
- OS << Trace << " " << Info.TakenCount << '\n';
- OS << formatv("E {0:$[,]}\n", EventNames.keys());
+ OS << 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/X86/pre-aggregated-records.s b/bolt/test/X86/pre-aggregated-records.s
index 98fcf08c677fd..29a1ae080de96 100644
--- a/bolt/test/X86/pre-aggregated-records.s
+++ b/bolt/test/X86/pre-aggregated-records.s
@@ -1,7 +1,7 @@
-## Test parsing of R (Return), r (FT_EXTERNAL_RETURN), and -1 hex (BR_ONLY)
-## records in pre-aggregated profiles, plus error paths for invalid record
-## types and malformed hex addresses. Closes e2e gaps that were previously
-## only exercised by unit tests.
+## Test parsing of R (Return), r (FT_EXTERNAL_RETURN), -1 hex (BR_ONLY),
+## and optional mispred counts in pre-aggregated profiles, plus error paths
+## for invalid record types and malformed hex addresses. Closes e2e gaps that
+## were previously only exercised by unit tests.
# REQUIRES: system-linux
@@ -9,10 +9,11 @@
# RUN: ld.lld %t.o -o %t
# RUN: link_fdata %s %t %t.preagg PREAGG
-## Parse R, r, B-with-neg1, T-with-neg1, plus a regular F as a sanity check.
+## Parse R, r, B-with-neg1, T-with-neg1, optional mispred counts, plus a
+## regular F as a sanity check.
# RUN: perf2bolt %t -p %t.preagg --pa -o %t.fdata 2>&1 \
# RUN: | FileCheck %s --check-prefix=CHECK-PARSE
-# CHECK-PARSE: read 6 aggregated brstack entries
+# CHECK-PARSE: read 9 aggregated brstack entries
## Error path: invalid record type letter.
# RUN: not perf2bolt %t -o %t.bad.fdata --pa \
@@ -58,3 +59,7 @@ Lretins:
# PREAGG: T #Lbr# #Ltrue# -1 4
## F: regular fall-through sanity check.
# PREAGG: F #Ltrue# #Lret# 3
+## Optional mispred count on B/T/R records.
+# PREAGG: B #Lbr# #Lfalse# 8
+# PREAGG: T #Lbr# #Lfalse# #Lret# 9 4
+# PREAGG: R #Lretins# #Lretins# #Lbr# 10 5
diff --git a/bolt/unittests/Profile/DataAggregator.cpp b/bolt/unittests/Profile/DataAggregator.cpp
index 0d5f4933189df..e5e4611a639c9 100644
--- a/bolt/unittests/Profile/DataAggregator.cpp
+++ b/bolt/unittests/Profile/DataAggregator.cpp
@@ -239,6 +239,33 @@ TEST_F(PreAggregatedX86TestHelper, ReturnEntry) {
EXPECT_EQ(Traces[0].second.TakenCount, 4u);
}
+TEST_F(PreAggregatedX86TestHelper, OptionalMispredField) {
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("B 100 200 1\n"
+ "T 300 400 500 3 4\n"
+ "R 600 700 800 5 6\n",
+ Traces);
+ ASSERT_EQ(Traces.size(), 3u);
+
+ EXPECT_EQ(Traces[0].first.Branch, 0x100ULL);
+ EXPECT_EQ(Traces[0].first.From, 0x200ULL);
+ EXPECT_EQ(Traces[0].first.To, Trace::BR_ONLY);
+ EXPECT_EQ(Traces[0].second.TakenCount, 1u);
+ EXPECT_EQ(Traces[0].second.MispredCount, 0u);
+
+ EXPECT_EQ(Traces[1].first.Branch, 0x300ULL);
+ EXPECT_EQ(Traces[1].first.From, 0x400ULL);
+ EXPECT_EQ(Traces[1].first.To, 0x500ULL);
+ EXPECT_EQ(Traces[1].second.TakenCount, 3u);
+ EXPECT_EQ(Traces[1].second.MispredCount, 4u);
+
+ EXPECT_EQ(Traces[2].first.Branch, 0x600ULL);
+ EXPECT_EQ(Traces[2].first.From, 0x700ULL);
+ EXPECT_EQ(Traces[2].first.To, 0x800ULL);
+ EXPECT_EQ(Traces[2].second.TakenCount, 5u);
+ EXPECT_EQ(Traces[2].second.MispredCount, 6u);
+}
+
TEST_F(PreAggregatedX86TestHelper, TraceWithNeg1AsBROnly) {
// T entry with -1 as fall-through target: parsed as BR_ONLY.
std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
More information about the llvm-commits
mailing list