[llvm] [BOLT][Perf2bolt] Add support to generate pre-parsed perf data (PR #171144)

Ádám Kallai via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 9 05:12:13 PST 2026


https://github.com/kaadam updated https://github.com/llvm/llvm-project/pull/171144

>From 7666df5b3e9345fdb001eea3dbac041be6e7b99f Mon Sep 17 00:00:00 2001
From: Adam Kallai <kadam at inf.u-szeged.hu>
Date: Mon, 8 Dec 2025 11:28:43 +0100
Subject: [PATCH 1/5] Spawn buildid-list perf job at start

---
 bolt/include/bolt/Profile/DataAggregator.h | 1 +
 bolt/lib/Profile/DataAggregator.cpp        | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 666df9eb18ed8..8bdb319748c61 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -163,6 +163,7 @@ class DataAggregator : public DataReader {
   };
 
   /// Process info for spawned processes
+  PerfProcessInfo BuildIDProcessInfo;
   PerfProcessInfo MainEventsPPI;
   PerfProcessInfo MemEventsPPI;
   PerfProcessInfo MMapEventsPPI;
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index a616d9db9db0e..7c6abe435fa2e 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -233,6 +233,8 @@ void DataAggregator::start() {
 
   launchPerfProcess("task events", TaskEventsPPI,
                     "script --show-task-events --no-itrace");
+
+  launchPerfProcess("buildid list", BuildIDProcessInfo, "buildid-list");
 }
 
 void DataAggregator::abort() {
@@ -303,8 +305,6 @@ void DataAggregator::processFileBuildID(StringRef FileBuildID) {
     errs() << "PERF-ERROR: return code " << ReturnCode << "\n" << ErrBuf;
   };
 
-  PerfProcessInfo BuildIDProcessInfo;
-  launchPerfProcess("buildid list", BuildIDProcessInfo, "buildid-list");
   if (prepareToParse("buildid", BuildIDProcessInfo, WarningCallback))
     return;
 

>From 0b15aad46d264c7ee50fb29ac368a72b7e3706e8 Mon Sep 17 00:00:00 2001
From: Adam Kallai <kadam at inf.u-szeged.hu>
Date: Mon, 8 Dec 2025 12:22:04 +0100
Subject: [PATCH 2/5] [BOLT][Perf2bolt] Add support to generate pre-parsed perf
 data

 The generator relies on the aggregator work to spawn the required
 perf-script jobs based on the the aggregation type, and merges
 the results of the pref-script jobs into a single file.
 This hybrid profile will contain all required events such as BuildID,
 MMAP, TASK, Branch/BrStack, or Memory event for the aggregation.
 The generator also creates a file header, where these events
 are listed along with the length information of their contents.

To generate a pre-parsed perf data as an input for BasicAggregation:

 `perf2bolt -p perf.data -o perf.text --ba --generate-perf-text-data`

Or for Spe BranchAggregation:

 `perf2bolt -p perf.data -o perf.text --spe --generate-perf-text-data`

The results place into the perf.text output file.
---
 bolt/include/bolt/Profile/DataAggregator.h | 70 ++++++++++++++++++++++
 bolt/lib/Profile/DataAggregator.cpp        | 69 ++++++++++++++++++++-
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 8bdb319748c61..99d32d1abc3d3 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -154,8 +154,24 @@ class DataAggregator : public DataReader {
   /// Perf utility full path name
   std::string PerfPath;
 
+  enum PerfProcessType {
+    BUILDIDS = 0,
+    MAIN_EVENTS,
+    MEN_EVENTS,
+    MMAP_EVENTS,
+    TASK_EVENTS
+  };
+  friend raw_ostream &operator<<(raw_ostream &OS, const PerfProcessType &T);
+
   /// Perf process spawning bookkeeping
   struct PerfProcessInfo {
+    static constexpr StringLiteral BuildIDEventStr = "BUILDIDS";
+    static constexpr StringLiteral MainEventStr = "MAIN";
+    static constexpr StringLiteral MemEventStr = "MEM";
+    static constexpr StringLiteral MMapEventStr = "MMAP";
+    static constexpr StringLiteral TaskEventsStr = "TASK";
+
+    enum PerfProcessType Type;
     bool IsFinished{false};
     sys::ProcessInfo PI;
     SmallVector<char, 256> StdoutPath;
@@ -244,6 +260,9 @@ class DataAggregator : public DataReader {
   /// parsing.
   void launchPerfProcess(StringRef Name, PerfProcessInfo &PPI, StringRef Args);
 
+  /// Helps to generate pre-parsed perf text profile.
+  uint64_t getFileSize(const StringRef File);
+
   /// Delete all temporary files created to hold the output generated by spawned
   /// subprocesses during the aggregation job
   void deleteTempFiles();
@@ -450,6 +469,35 @@ class DataAggregator : public DataReader {
   /// an external tool.
   std::error_code parsePreAggregatedLBRSamples();
 
+  /// Dump pre-parsed perf profile data into a single file.
+  /// The generator relies on the aggregator work to spawn the required
+  /// perf-script jobs based on the the aggregation type, and merges
+  /// the results of the pref-script jobs into a single file.
+  /// This hybrid profile contains all required events such as BuildID,
+  /// MMAP, TASK, Branch/BrStack, or Memory for the aggregation.
+  /// The generator also creates a file header, where these events
+  /// are listed along with the length information of their contents.
+  /// This is how a pre-parsed profile data looks like for Basic Aggregation:
+  ///
+  /// perf2bolt -p perf.data -o perf.text --ba --generate-perf-text-data
+  ///
+  /// PERFTEXT BUILDIDS=55;MMAP=2523121;MAIN=6426;TASK=352203;
+  /// 68c3da33ca43d5a74d501b5ea0012f782e04096e /example/bin1
+  /// c3a8496f2347b468a54a21072dc6cde7f0d88c6c /example/bin2
+  /// ...
+  /// bin1   20470 ... PERF_RECORD_MMAP2 20470/20470: ... r-xp /example/bin1
+  /// bin1   20470 ... PERF_RECORD_MMAP2 20470/20470: ... r-xp [vdso]
+  /// ...
+  /// bin1   20470 ... PERF_RECORD_COMM exec: bin1:20470/20470
+  /// bin1   20470 ... PERF_RECORD_EXIT(20470:20470):(20469:20469)
+  /// ...
+  /// 20470 branch: ffffffd1a4764d04 ffffffd1a4764cfc
+  /// 20470 branch: ffffffd1a44777f4 ffffffd1a4fc8af0
+  /// 20470 branch: ffffffd1a477cd14 ffffffd1a477cd00
+  /// 20470 branch: ffffffd1a4400f58 ffffffd1a4400f7c
+  /// ...
+  void generatePerfTextData();
+
   /// If \p Address falls into the binary address space based on memory
   /// mapping info \p MMI, then adjust it for further processing by subtracting
   /// the base load address. External addresses, i.e. addresses that do not
@@ -600,6 +648,28 @@ inline raw_ostream &operator<<(raw_ostream &OS,
     OS << " ... " << Twine::utohexstr(T.To);
   return OS;
 }
+
+inline raw_ostream &operator<<(raw_ostream &OS,
+                               const DataAggregator::PerfProcessType &T) {
+  switch (T) {
+  case DataAggregator::PerfProcessType::BUILDIDS:
+    OS << DataAggregator::PerfProcessInfo::BuildIDEventStr;
+    break;
+  case DataAggregator::PerfProcessType::MAIN_EVENTS:
+    OS << DataAggregator::PerfProcessInfo::MainEventStr;
+    break;
+  case DataAggregator::PerfProcessType::MEN_EVENTS:
+    OS << DataAggregator::PerfProcessInfo::MemEventStr;
+    break;
+  case DataAggregator::PerfProcessType::MMAP_EVENTS:
+    OS << DataAggregator::PerfProcessInfo::MMapEventStr;
+    break;
+  case DataAggregator::PerfProcessType::TASK_EVENTS:
+    OS << DataAggregator::PerfProcessInfo::TaskEventsStr;
+    break;
+  }
+  return OS;
+}
 } // namespace bolt
 } // namespace llvm
 
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index 7c6abe435fa2e..3d6c980f3cfd4 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -127,6 +127,11 @@ cl::opt<std::string>
                             "perf-script output in a textual format"),
                    cl::ReallyHidden, cl::init(""), cl::cat(AggregatorCategory));
 
+cl::opt<bool> GeneratePerfTextProfile(
+    "generate-perf-text-data",
+    cl::desc("Dump perf-script jobs' output into output file"), cl::Hidden,
+    cl::cat(AggregatorCategory));
+
 static cl::opt<bool>
 TimeAggregator("time-aggr",
   cl::desc("time BOLT aggregator"),
@@ -141,6 +146,8 @@ namespace {
 const char TimerGroupName[] = "aggregator";
 const char TimerGroupDesc[] = "Aggregator";
 
+constexpr const StringLiteral PerfTextMagicStr = "PERFTEXT";
+
 std::vector<SectionNameAndRange> getTextSections(const BinaryContext *BC) {
   std::vector<SectionNameAndRange> sections;
   for (BinarySection &Section : BC->sections()) {
@@ -169,6 +176,17 @@ void deleteTempFile(const std::string &FileName) {
 }
 }
 
+uint64_t DataAggregator::getFileSize(const StringRef File) {
+  uint64_t Size;
+  std::error_code EC = sys::fs::file_size(File, Size);
+  if (EC) {
+    errs() << "unable to obtain file size: " << EC.message() << "\n";
+    deleteTempFiles();
+    exit(1);
+  }
+  return Size;
+}
+
 void DataAggregator::deleteTempFiles() {
   for (std::string &FileName : TempFiles)
     deleteTempFile(FileName);
@@ -382,6 +400,53 @@ void DataAggregator::parsePreAggregated() {
   }
 }
 
+void DataAggregator::generatePerfTextData() {
+  std::error_code EC;
+  raw_fd_ostream OutFile(opts::OutputFilename, EC, sys::fs::OpenFlags::OF_None);
+  if (EC) {
+    errs() << "error opening output file: " << EC.message() << "\n";
+    deleteTempFiles();
+    exit(1);
+  }
+
+  SmallVector<PerfProcessInfo *, 5> ProcessInfos = {
+      &BuildIDProcessInfo, &MMapEventsPPI, &MainEventsPPI, &TaskEventsPPI};
+  if (opts::ParseMemProfile)
+    ProcessInfos.push_back(&MemEventsPPI);
+
+  // Create a file header as a table of the contents
+  // PERFTEXT;EVENT1={$SIZE};EVENT2={$SIZE}...
+  OutFile << PerfTextMagicStr << ";";
+  for (const auto PPI : ProcessInfos) {
+    std::string Error;
+    sys::Wait(PPI->PI, std::nullopt, &Error);
+    if (!Error.empty()) {
+      errs() << "PERF-ERROR: " << PerfPath << ": " << Error << "\n";
+      deleteTempFiles();
+      exit(1);
+    }
+    uint64_t FS = getFileSize(PPI->StdoutPath.data());
+    OutFile << PPI->Type << "=" << FS << ";";
+  }
+  OutFile << "\n";
+
+  // Merge all perf-scripts jobs' output into the single OutputFile
+  for (const auto PPI : ProcessInfos) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
+        MemoryBuffer::getFileOrSTDIN(PPI->StdoutPath.data());
+    if (std::error_code EC = MB.getError()) {
+      errs() << "Cannot open " << PPI->StdoutPath.data() << ": " << EC.message()
+             << "\n";
+      deleteTempFiles();
+      exit(1);
+    }
+    OutFile << (*MB)->getBuffer();
+  }
+  OutFile.close();
+  deleteTempFiles();
+  exit(0);
+}
+
 void DataAggregator::filterBinaryMMapInfo() {
   if (opts::FilterPID) {
     auto MMapInfoIter = BinaryMMapInfo.find(opts::FilterPID);
@@ -594,7 +659,9 @@ void DataAggregator::imputeFallThroughs() {
 Error DataAggregator::preprocessProfile(BinaryContext &BC) {
   this->BC = &BC;
 
-  if (opts::ReadPreAggregated) {
+  if (opts::GeneratePerfTextProfile) {
+    generatePerfTextData();
+  } else if (opts::ReadPreAggregated) {
     parsePreAggregated();
   } else {
     parsePerfData(BC);

>From cd5bdf40a345f73ca225ff01a712c4bcfc867fb6 Mon Sep 17 00:00:00 2001
From: Adam Kallai <kadam at inf.u-szeged.hu>
Date: Mon, 19 Jan 2026 16:25:07 +0100
Subject: [PATCH 3/5] Address reviewers 1

---
 bolt/include/bolt/Profile/DataAggregator.h | 62 +++++++++++++---------
 bolt/lib/Profile/DataAggregator.cpp        | 37 ++++++++-----
 2 files changed, 62 insertions(+), 37 deletions(-)

diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 99d32d1abc3d3..4510d7b85abe7 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -157,7 +157,7 @@ class DataAggregator : public DataReader {
   enum PerfProcessType {
     BUILDIDS = 0,
     MAIN_EVENTS,
-    MEN_EVENTS,
+    MEM_EVENTS,
     MMAP_EVENTS,
     TASK_EVENTS
   };
@@ -173,17 +173,17 @@ class DataAggregator : public DataReader {
 
     enum PerfProcessType Type;
     bool IsFinished{false};
-    sys::ProcessInfo PI;
-    SmallVector<char, 256> StdoutPath;
-    SmallVector<char, 256> StderrPath;
+    sys::ProcessInfo PI{};
+    SmallVector<char, 256> StdoutPath{};
+    SmallVector<char, 256> StderrPath{};
   };
 
   /// Process info for spawned processes
-  PerfProcessInfo BuildIDProcessInfo;
-  PerfProcessInfo MainEventsPPI;
-  PerfProcessInfo MemEventsPPI;
-  PerfProcessInfo MMapEventsPPI;
-  PerfProcessInfo TaskEventsPPI;
+  PerfProcessInfo BuildIDProcessInfo = {PerfProcessType::BUILDIDS};
+  PerfProcessInfo MainEventsPPI = {PerfProcessType::MAIN_EVENTS};
+  PerfProcessInfo MemEventsPPI = {PerfProcessType::MEM_EVENTS};
+  PerfProcessInfo MMapEventsPPI = {PerfProcessType::MMAP_EVENTS};
+  PerfProcessInfo TaskEventsPPI = {PerfProcessType::TASK_EVENTS};
 
   /// Kernel VM starts at fixed based address
   /// https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt
@@ -472,29 +472,41 @@ class DataAggregator : public DataReader {
   /// Dump pre-parsed perf profile data into a single file.
   /// The generator relies on the aggregator work to spawn the required
   /// perf-script jobs based on the the aggregation type, and merges
-  /// the results of the pref-script jobs into a single file.
+  /// their results into a single file.
   /// This hybrid profile contains all required events such as BuildID,
-  /// MMAP, TASK, Branch/BrStack, or Memory for the aggregation.
+  /// MMAP, TASK, MAIN (brstack or basic samples), or MEM for the aggregation.
   /// The generator also creates a file header, where these events
   /// are listed along with the length information of their contents.
-  /// This is how a pre-parsed profile data looks like for Basic Aggregation:
+  /// The given length numbers in the header are in bytes, they are used
+  /// as an offset int the pre-parsed profile.
+  /// Some of these events are essential to be presented in the file.
+  /// Please see a short summary below:
+  /// MEM: Optional. Parsing memory profile is enabled by default, unless
+  /// '--itrace' aggregation is set (like Arm SPE). In the latter case
+  /// MEM profile won't be added into the pre-parsed profile.
+  /// MMAP: Compulsory, the mmap data is required to be in the file.
+  /// BUILDID: Ignored (you should use --ignore-build-id),
+  /// if buildid information doesn't exist in the input profile.
+  /// TASK: When task related data exists in the input profile,
+  /// Perf2bolt will always parse it.
+  /// MAIN: Compulsory; the MAIN events always have to be represented in the
+  /// file. Main events could be either 'brstack' or 'basic' sample data
+  /// based on how it was collected by Linux Perf.
   ///
-  /// perf2bolt -p perf.data -o perf.text --ba --generate-perf-text-data
+  /// Example how you can generate pre-parsed profile for 'basic' aggregation:
+  /// perf2bolt -p perf.data BINARY -o perf.text --ba --generate-perf-text-data
   ///
-  /// PERFTEXT BUILDIDS=55;MMAP=2523121;MAIN=6426;TASK=352203;
-  /// 68c3da33ca43d5a74d501b5ea0012f782e04096e /example/bin1
-  /// c3a8496f2347b468a54a21072dc6cde7f0d88c6c /example/bin2
+  /// This is how a pre-parsed profile data looks like for Basic Aggregation:
+  /// PERFTEXT;BUILDIDS=50;MMAP=3000000;MAIN=5000;TASK=350000;
+  /// abcd1234 /example/bin1
   /// ...
-  /// bin1   20470 ... PERF_RECORD_MMAP2 20470/20470: ... r-xp /example/bin1
-  /// bin1   20470 ... PERF_RECORD_MMAP2 20470/20470: ... r-xp [vdso]
+  /// bin1   1234 ... PERF_RECORD_MMAP2 1234/1234: ... r-xp /example/bin1
   /// ...
-  /// bin1   20470 ... PERF_RECORD_COMM exec: bin1:20470/20470
-  /// bin1   20470 ... PERF_RECORD_EXIT(20470:20470):(20469:20469)
+  /// bin1   1234 ... PERF_RECORD_COMM exec: bin1:1234/1234
+  /// bin1   1234 ... PERF_RECORD_EXIT(1234:1234):(20469:20469)
   /// ...
-  /// 20470 branch: ffffffd1a4764d04 ffffffd1a4764cfc
-  /// 20470 branch: ffffffd1a44777f4 ffffffd1a4fc8af0
-  /// 20470 branch: ffffffd1a477cd14 ffffffd1a477cd00
-  /// 20470 branch: ffffffd1a4400f58 ffffffd1a4400f7c
+  /// 1234 branch: ffffffd1a4764d04 ffffffd1a4764cfc
+  /// 1234 branch: ffffffd1a44777f4 ffffffd1a4fc8af0
   /// ...
   void generatePerfTextData();
 
@@ -658,7 +670,7 @@ inline raw_ostream &operator<<(raw_ostream &OS,
   case DataAggregator::PerfProcessType::MAIN_EVENTS:
     OS << DataAggregator::PerfProcessInfo::MainEventStr;
     break;
-  case DataAggregator::PerfProcessType::MEN_EVENTS:
+  case DataAggregator::PerfProcessType::MEM_EVENTS:
     OS << DataAggregator::PerfProcessInfo::MemEventStr;
     break;
   case DataAggregator::PerfProcessType::MMAP_EVENTS:
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index 3d6c980f3cfd4..fbbb0c3e064d9 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -323,6 +323,7 @@ void DataAggregator::processFileBuildID(StringRef FileBuildID) {
     errs() << "PERF-ERROR: return code " << ReturnCode << "\n" << ErrBuf;
   };
 
+  // Extract buildid information from the input profile in the start() function.
   if (prepareToParse("buildid", BuildIDProcessInfo, WarningCallback))
     return;
 
@@ -414,35 +415,47 @@ void DataAggregator::generatePerfTextData() {
   if (opts::ParseMemProfile)
     ProcessInfos.push_back(&MemEventsPPI);
 
-  // Create a file header as a table of the contents
-  // PERFTEXT;EVENT1={$SIZE};EVENT2={$SIZE}...
-  OutFile << PerfTextMagicStr << ";";
+  // Create a file header as a table of the contents.
+  // Initially pre-allocate enough space for the header at the beginning of
+  // the file.
+  // The header can be maximum 132 character, this number is pre-calculated,
+  // the sum of the length of the magic strings, event names, their sizes,
+  // and the field separators.
+  // PERFTEXT;EVENT1={0x$SIZE};EVENT2={0x$SIZE}...
+  // The size of the events are printed in hex format (16 width) in order to be
+  // predictable fixed length.
+  OutFile << std::string(132, ' ') << "\n";
+  std::string Header;
+  raw_string_ostream SS(Header);
+  SS << PerfTextMagicStr << ";";
   for (const auto PPI : ProcessInfos) {
     std::string Error;
+    auto PathData = PPI->StdoutPath.data();
     sys::Wait(PPI->PI, std::nullopt, &Error);
     if (!Error.empty()) {
       errs() << "PERF-ERROR: " << PerfPath << ": " << Error << "\n";
       deleteTempFiles();
       exit(1);
     }
-    uint64_t FS = getFileSize(PPI->StdoutPath.data());
-    OutFile << PPI->Type << "=" << FS << ";";
-  }
-  OutFile << "\n";
 
-  // Merge all perf-scripts jobs' output into the single OutputFile
-  for (const auto PPI : ProcessInfos) {
+    SS << PPI->Type << formatv("={0:x16};", getFileSize(PathData));
+
+    // Merge all perf-scripts jobs' output into the single OutputFile
     ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
-        MemoryBuffer::getFileOrSTDIN(PPI->StdoutPath.data());
+        MemoryBuffer::getFileOrSTDIN(PathData);
     if (std::error_code EC = MB.getError()) {
-      errs() << "Cannot open " << PPI->StdoutPath.data() << ": " << EC.message()
-             << "\n";
+      errs() << "Cannot open " << PathData << ": " << EC.message() << "\n";
       deleteTempFiles();
       exit(1);
     }
     OutFile << (*MB)->getBuffer();
   }
+
+  OutFile.seek(0);
+  OutFile << Header;
   OutFile.close();
+  outs() << "PERF2BOLT: Profile is saved to file " << opts::OutputFilename
+         << "\n";
   deleteTempFiles();
   exit(0);
 }

>From 625f07aee1d76bbff2b85cf3bedc58098bbd1ada Mon Sep 17 00:00:00 2001
From: Adam Kallai <kadam at inf.u-szeged.hu>
Date: Wed, 21 Jan 2026 16:24:20 +0100
Subject: [PATCH 4/5] Update the description

---
 bolt/include/bolt/Profile/DataAggregator.h | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 4510d7b85abe7..b14cd67b86dcc 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -482,12 +482,13 @@ class DataAggregator : public DataReader {
   /// Some of these events are essential to be presented in the file.
   /// Please see a short summary below:
   /// MEM: Optional. Parsing memory profile is enabled by default, unless
-  /// '--itrace' aggregation is set (like Arm SPE). In the latter case
-  /// MEM profile won't be added into the pre-parsed profile.
+  /// '--itrace' aggregation is set. In the latter case MEM profile
+  /// won't be added into the pre-parsed profile. Note that, currently
+  /// mem events only supported if they were gathered on X86_64.
   /// MMAP: Compulsory, the mmap data is required to be in the file.
   /// BUILDID: Ignored (you should use --ignore-build-id),
   /// if buildid information doesn't exist in the input profile.
-  /// TASK: When task related data exists in the input profile,
+  /// TASK: If task related data exists in the input profile,
   /// Perf2bolt will always parse it.
   /// MAIN: Compulsory; the MAIN events always have to be represented in the
   /// file. Main events could be either 'brstack' or 'basic' sample data
@@ -497,7 +498,8 @@ class DataAggregator : public DataReader {
   /// perf2bolt -p perf.data BINARY -o perf.text --ba --generate-perf-text-data
   ///
   /// This is how a pre-parsed profile data looks like for Basic Aggregation:
-  /// PERFTEXT;BUILDIDS=50;MMAP=3000000;MAIN=5000;TASK=350000;
+  /// PERFTEXT;BUILDIDS=0x0000000000000032;MMAP=0x000000000002DC6C0;MAIN=0x00000000000001388;
+  /// TASK=0x00000000000055730;MEM=0x0000000000000128;
   /// abcd1234 /example/bin1
   /// ...
   /// bin1   1234 ... PERF_RECORD_MMAP2 1234/1234: ... r-xp /example/bin1
@@ -505,9 +507,11 @@ class DataAggregator : public DataReader {
   /// bin1   1234 ... PERF_RECORD_COMM exec: bin1:1234/1234
   /// bin1   1234 ... PERF_RECORD_EXIT(1234:1234):(20469:20469)
   /// ...
-  /// 1234 branch: ffffffd1a4764d04 ffffffd1a4764cfc
-  /// 1234 branch: ffffffd1a44777f4 ffffffd1a4fc8af0
+  /// 1234 branch: abcd1234 abcd1237
+  /// 1234 branch: abcd5678 abce9876
   /// ...
+  /// 1234 mem-loads: efgh1234 efgh1234
+  /// 1234 mem-loads: efgh4567 efgh8910
   void generatePerfTextData();
 
   /// If \p Address falls into the binary address space based on memory

>From c9167081fe68cc9240932a8ec0274fa958a4460a Mon Sep 17 00:00:00 2001
From: Adam Kallai <kadam at inf.u-szeged.hu>
Date: Mon, 26 Jan 2026 16:49:01 +0100
Subject: [PATCH 5/5] Print hex without 0x prefix

---
 bolt/lib/Profile/DataAggregator.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index fbbb0c3e064d9..3c3da064769af 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -438,7 +438,7 @@ void DataAggregator::generatePerfTextData() {
       exit(1);
     }
 
-    SS << PPI->Type << formatv("={0:x16};", getFileSize(PathData));
+    SS << PPI->Type << formatv("={0:x-16};", getFileSize(PathData));
 
     // Merge all perf-scripts jobs' output into the single OutputFile
     ErrorOr<std::unique_ptr<MemoryBuffer>> MB =



More information about the llvm-commits mailing list