[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:33 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