[llvm] [BOLT] Add pre-parsed perf script support (PR #163785)
Ádám Kallai via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 9 06:09:19 PST 2026
https://github.com/kaadam updated https://github.com/llvm/llvm-project/pull/163785
>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/7] 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/7] [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/7] 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/7] 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/7] 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 =
>From bead6213543f7aaa65fc7e055f2d311694cf08e2 Mon Sep 17 00:00:00 2001
From: Adam Kallai <kadam at inf.u-szeged.hu>
Date: Mon, 8 Dec 2025 16:47:24 +0100
Subject: [PATCH 6/7] Add support to read and parse pre-aggregated profile
This PR implements the functionality to read and parse a pre-paresed
perf-script profile which was made by Perf2bolt's
'--generate-perf-text-data' option.
It helps to add support for large ARM Spe end-to-end tests.
Why does the test need to have a textual format Spe profile?
- To collect an Arm Spe profile by Linux Perf, it needs to have
an arm developer device which has Spe support.
- To decode Spe data, it also needs to have the proper version of
Linux Perf.
The minimum required version of Linux Perf is v6.15.
Bypassing these technical difficulties, that easier to prove
a pre-generated textual profile format.
How should generate this type of profile?
1) You can use Perf2bolt itself to generate a pre-parsed perf-script profile
in textual format.
$ perf2bolt BINARY -p perf.data -o test.text --spe --generate-perf-text-data
2) Perf2bolt is able to work with this type of profile:
$ perf2bolt BINARY -o test.fdata -p test.text --spe -perf-text-data
---
bolt/include/bolt/Profile/DataAggregator.h | 15 +++
bolt/lib/Profile/DataAggregator.cpp | 129 +++++++++++++++++++--
bolt/test/perf2bolt/Inputs/perf_test | Bin 0 -> 142568 bytes
3 files changed, 133 insertions(+), 11 deletions(-)
create mode 100755 bolt/test/perf2bolt/Inputs/perf_test
diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index b14cd67b86dcc..f7a2321acb26a 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -176,6 +176,8 @@ class DataAggregator : public DataReader {
sys::ProcessInfo PI{};
SmallVector<char, 256> StdoutPath{};
SmallVector<char, 256> StderrPath{};
+ uint64_t Length{0};
+ uint64_t Offset{0};
};
/// Process info for spawned processes
@@ -469,6 +471,19 @@ class DataAggregator : public DataReader {
/// an external tool.
std::error_code parsePreAggregatedLBRSamples();
+ /// Coordinate reading and parsing pre-parsed perf-script trace created by
+ /// Perf2bolt's '--generate-perf-text-data' option.
+ ///
+ /// We process the special header of the pre-parsed profile first to
+ /// determine an offset/length pairs for each events.
+ /// Later based on these information we open only a slice of the pre-parsed
+ /// file which belongs to the required event. After the preparation
+ /// parsePerfData function is invoked.
+ void parsePerfTextData(BinaryContext &BC);
+
+ /// Parse the header of the perf text file.
+ std::error_code parsePerfTextFileHeader();
+
/// 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
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index 3c3da064769af..e79f32e9bedcf 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -121,11 +121,11 @@ cl::opt<bool> ReadPreAggregated(
"pa", cl::desc("skip perf and read data from a pre-aggregated file format"),
cl::cat(AggregatorCategory));
-cl::opt<std::string>
- ReadPerfEvents("perf-script-events",
- cl::desc("skip perf event collection by supplying a "
- "perf-script output in a textual format"),
- cl::ReallyHidden, cl::init(""), cl::cat(AggregatorCategory));
+cl::opt<bool> ReadPerfTextData(
+ "perf-text-data",
+ cl::desc("skip perf event collection by reading a "
+ "pre-parsed perf-script output in a textual format"),
+ cl::Hidden, cl::cat(AggregatorCategory));
cl::opt<bool> GeneratePerfTextProfile(
"generate-perf-text-data",
@@ -212,7 +212,7 @@ void DataAggregator::start() {
// Don't launch perf for pre-aggregated files or when perf input is specified
// by the user.
- if (opts::ReadPreAggregated || !opts::ReadPerfEvents.empty())
+ if (opts::ReadPreAggregated || opts::ReadPerfTextData)
return;
findPerfExecutable();
@@ -355,7 +355,7 @@ void DataAggregator::processFileBuildID(StringRef FileBuildID) {
}
bool DataAggregator::checkPerfDataMagic(StringRef FileName) {
- if (opts::ReadPreAggregated)
+ if (opts::ReadPreAggregated || opts::ReadPerfTextData)
return true;
Expected<sys::fs::file_t> FD = sys::fs::openNativeFileForRead(FileName);
@@ -401,6 +401,97 @@ void DataAggregator::parsePreAggregated() {
}
}
+std::error_code DataAggregator::parsePerfTextFileHeader() {
+ size_t LineEnd = ParsingBuf.find_first_of("\n");
+ if (LineEnd == StringRef::npos) {
+ reportError("expected rest of line");
+ Diag << "Found: " << ParsingBuf << "\n";
+ return make_error_code(llvm::errc::io_error);
+ }
+ StringRef HeaderLine = ParsingBuf.substr(0, LineEnd);
+ size_t HeaderLineSize = HeaderLine.size() + 1;
+
+ if (!HeaderLine.consume_front(PerfTextMagicStr)) {
+ reportError("expected 'PERFTEXT' magic string");
+ Diag << "Found: " << HeaderLine << "\n";
+ return make_error_code(llvm::errc::io_error);
+ }
+ Col += PerfTextMagicStr.size();
+
+ SmallVector<StringRef, 5> Events;
+ HeaderLine.trim().split(Events, ";", -1, false);
+
+ if (Events.empty()) {
+ reportError("missing events=sizes content");
+ Diag << "Found: " << HeaderLine << "\n";
+ return make_error_code(llvm::errc::io_error);
+ }
+
+ uint64_t Offset = HeaderLineSize;
+ uint64_t Length = 0;
+ for (StringRef EV : Events) {
+ StringRef EventStr, LengthStr;
+ std::tie(EventStr, LengthStr) = EV.split("=");
+
+ PerfProcessInfo *PPI =
+ StringSwitch<PerfProcessInfo *>(EventStr)
+ .Case(PerfProcessInfo::BuildIDEventStr, &BuildIDProcessInfo)
+ .Case(PerfProcessInfo::MainEventStr, &MainEventsPPI)
+ .Case(PerfProcessInfo::MemEventStr, &MemEventsPPI)
+ .Case(PerfProcessInfo::MMapEventStr, &MMapEventsPPI)
+ .Case(PerfProcessInfo::TaskEventsStr, &TaskEventsPPI)
+ .Default(nullptr);
+
+ if (!PPI) {
+ reportError("malformed text profile");
+ Diag << "Found: " << EventStr << " in " << HeaderLine << "\n";
+ return make_error_code(llvm::errc::io_error);
+ }
+
+ if (LengthStr.getAsInteger(16, Length)) {
+ reportError("expected hexadecimal number");
+ Diag << "Found: " << LengthStr << " in " << HeaderLine << "\n";
+ return make_error_code(llvm::errc::io_error);
+ }
+ PPI->Offset = Offset;
+ PPI->Length = Length;
+ Offset = Offset + Length;
+ Col += EV.size();
+ }
+ uint64_t FS = getFileSize(Filename);
+ if (FS != Offset) {
+ reportError("corrupted perf text profile");
+ Diag << "Found: " << FS << " != " << Offset << "\n";
+ return make_error_code(llvm::errc::io_error);
+ }
+ return std::error_code();
+}
+
+void DataAggregator::parsePerfTextData(BinaryContext &BC) {
+ outs() << "PERF2BOLT: parsing a hybrid perf-script events...\n";
+ NamedRegionTimer T("parsePerfTextData", "Parsing perf-script events",
+ TimerGroupName, TimerGroupDesc, opts::TimeAggregator);
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ if (std::error_code EC = MB.getError()) {
+ errs() << "PERF2BOLT-ERROR: cannot open " << Filename << ": "
+ << EC.message() << "\n";
+ exit(1);
+ }
+
+ ParsingBuf = (*MB)->getBuffer();
+ Col = 0;
+ Line = 1;
+ if (std::error_code EC = parsePerfTextFileHeader()) {
+ errs() << "PERF2BOLT-ERROR: failed to parse text header" << EC.message()
+ << "\n";
+ exit(1);
+ }
+
+ parsePerfData(BC);
+}
+
void DataAggregator::generatePerfTextData() {
std::error_code EC;
raw_fd_ostream OutFile(opts::OutputFilename, EC, sys::fs::OpenFlags::OF_None);
@@ -489,10 +580,24 @@ void DataAggregator::filterBinaryMMapInfo() {
int DataAggregator::prepareToParse(StringRef Name, PerfProcessInfo &Process,
PerfProcessErrorCallbackTy Callback) {
- if (!opts::ReadPerfEvents.empty()) {
- outs() << "PERF2BOLT: using pre-processed perf events for '" << Name
- << "' (perf-script-events)\n";
- ParsingBuf = opts::ReadPerfEvents;
+ if (opts::ReadPerfTextData) {
+ if (Process.Length == 0) {
+ errs() << "PERF2BOLT-WARNING: your input profile was generated with "
+ << "parsing " << Process.Type << " event enabled. "
+ << "This data is missing from your pre-parsed profile.\n";
+ }
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
+ MemoryBuffer::getFileSlice(Filename, Process.Length, Process.Offset);
+ if (std::error_code EC = MB.getError()) {
+ errs() << "Cannot open " << Process.Type << ": " << EC.message() << "\n";
+ exit(1);
+ }
+
+ FileBuf = std::move(*MB);
+ ParsingBuf = FileBuf->getBuffer();
+ Col = 0;
+ Line = 1;
return 0;
}
@@ -676,6 +781,8 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) {
generatePerfTextData();
} else if (opts::ReadPreAggregated) {
parsePreAggregated();
+ } else if (opts::ReadPerfTextData) {
+ parsePerfTextData(BC);
} else {
parsePerfData(BC);
}
diff --git a/bolt/test/perf2bolt/Inputs/perf_test b/bolt/test/perf2bolt/Inputs/perf_test
new file mode 100755
index 0000000000000000000000000000000000000000..50d930355a5c0d88306f5bb71b091018e8e5910b
GIT binary patch
literal 142568
zcmeI$TWnm#8Nl(`bpinbHX#8MOtOMf8PP23E9Me#E}LwG9n#>ar4l_^@2>4_*Sqds
zsDtV at B@|&?q_nC~E4302JU~^cJWz>;sx=KFAo>uhs-o>nRDl!(t=u*(Zb{>QbIyGB
z$+0cyP3pt{MC&>8&3rR+emT2mcE6Gy*b|S%j2=zqZeweQTbuk)ziSw~DelgU={J4m
zGWom3w3&+}x<+38t~FYYxil@;xqfzZoA<11kCtt&pO(5pTiU$Uj?C4;fLfZCpr_4S
zE3d<?LAzd`mi=xWT88uNH744E4vDs4b}ip at 3)3>1*SaOhYu#^WH%7~pUo)n|m6~UJ
z+xb#%zLc9!%ctFZTB_&4x9fSkvX8n>H;g&p^6uIctaDlE)_0dH)&7%`XV>|!9yZ^;
zUJj;PRwmqlTIzhamWso at -M5zV+e*c9V{+SMU+=cw?qsc!?DWU8|IPNA_U=FAk6`aF
zH-%s44+01vfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*sr
zAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_0
z00IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b@
z2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000Iag
zfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}
z0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*sr
zAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_0
z00IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b@
z2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000Iag
zfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}
z0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*sr
zAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2q1s}0tg_0
z00IagfB*srAb<b at 2q1s}0tg_000IagfB*srAb<b at 2p|v>f(<J$TqUu at 3h^6OiQm0S
z{L>P*Im?f at iTVGU<Zs-JN{1HLsj<0ui7`#)3oiD;H=er4NS~?DAa>mnlw4yrhvNRJ
z=aq`XIj>gFR_oq)wpccvH#%M^yNGAJeM5s at zECZU7HjoFb!c!`sZuTsWrs_Jpl#(A
zFE^R>MvCQZsrYcg*g2B5O0w7N9oV;Xm)Du>O!h3EcXj(qNwlr;%XPZOYn%MD_DH<n
z#S{D2UeI6br>+mi(QDS>-VDX#8kF*MC?3ohG at c2?gAs%HTqqu_Ac*(7^;|5~aNPc%
z#jb0*vrpo7O&@EDnIS1Ru8Em3DZ8b7T*@ISpOvyM<*QOYBjp(>H_FQ%v4;<u*knuW
zy7d>YJ1+m3_8w at H*Q at cE`MB+{`{EW`Ps!^UnZv(VcU;l(SbW#z7Y$01#BKY54{4up
z?e at Mln!kT3|F~;!54Y!*+Mk#B3o?Hx+#VkdI at lNo0xJmoxp~XqJAS`!`i;+Krhk_?
z_SW2ip>)S=$7`7<w`b*cU)Xf-+L$@}^Tk8r(>-yMd2;O|wzz%1z9}=awpTi3zBXIG
zWZ`u4)}wZs6Rwp05BU9i4%*`8^O@<n%u9c`C-c&LQzrIG=8g09jWWPL<ZWjMShsL`
zq<QP^rF^@-quaMju4&wID06K4Z=|QmOut=UpPAWyzB_Kt6eVybzp$|I%GyoRFZQ6!
zy*R(kf9H$R=&s<9q)tzrn{Ld{q|Y^_=N~*VVvl6=)<=Dv3)*k_koM*uYKKVv{B+~&
zv8l7BammT_IXmvVm(HZ;zw`do+3EB-nb<CIX}-*{_gY-Plj->u>3%YO)_!oDOwY-+
znXgXG_3vypQ at 71b&CfK>p6Qdzai at bzr^8F9_IhX1bH`?5)9JZ)XFFyy$6juE at PxIH
zxz>sIlzdcJ at A$$gX<K)~EVlVInbaK%J>Tz&n}wTxAb*>;_RE>AkJ;9DPRlgfkMjRR
zz}_$Ru=^Eze6X-k3C at hYqs%5((ZW7A?QwWx at O1V&NqyD^<&cezf3&*tZ*Dw&W?$pt
ziA_PiKI65&_G@>~X??Ehy!P2_k24#B%*%qR(R_WT|MIG!{ZiNdxGVp1KDfRYUHi2z
zuKSnkTwSkA_hP#5vCn3EX#4u0Y6dn3E5F>;$6S5RUH_z;@4Tx&>gw{A at V)i_!KMGt
zi<H~1MJIa7t=kL~%bzb)???;`>`rucCR52&qJ6Yj at 0ZtDV>p?sjNefzJv4r+{j+VN
zTKQZdS5Hb~qPNi3)6+51aoccbZ%3-*_EgvHy<Od1xm at 2!N7ryqXJ0<o)78<NzuDwU
z+45-Op+dD*td!j(c7*@-JbQQTx+BqkXt+_XHxeCP$*yE-TW`a!c7D0DJDKXf*@dGT
zOLhDIWA}(JyBjv)n(Y0z#{6;F=i1eN|ErDecU^aLqnyOe<>q*+-swS$-FMpfY$SfK
ziyOC}4tg7tm6Mpc)@0oKMDL$*KYpdr`&IjYOHS<gx-ZxG({f^Wp?d#o{JSz>EPl<h
z_5V~ltaQDvuM+>2KmK|%>E7=;{%8F0m-~ERJH%U!zW=rVFYE=zuQJj5cE7~q at hcYJ
zf7*Y at k2f2AA8Pz9IoTi%hn=&(Czsf}E`HiM`}<;v&B-evpMtH<S*reVrHp^2xzzNz
z>ssUD35l=t{j*czEh~(3kHix$H(ZRY5`Scs_;V7!Av}OPe^KK0dJnkk(zX5A#U~>1
zpSk#P7x%wk$XKtt`13B_u5%@eW%<TAVUp!ay^!3obKkalcGM*EN6NJ$<0d&;ZY141
z{DO*C4XR_=+E~!LE|F at Xl(nhuY@$?`vr0Z&&n9!Vdbddy#=MbgcD&$?<)ypUOtM~>
zl&-~cQU1yo+M-GNx%Sk{R;$?~L8G3_6xs1&PL@!S1UtSAG4AE;w`Q;Ie{J at oc0tKf
zC6_JvU4ub~Yc*p(|HcbtNtUaW1S!XA^=fbyl=2-tJ6x2}Moq3-uhko}Ys^VdzMOjl
z`|cm|JhSwT-P74?M!%|uLY|kec%!AtaJJ;->y>KF%QhyBEMcNls2B3dlnlE<5Bt^L
zUA`x4tsXIfUA{3sene72HP6xoI<D(Pp*rH#3$?l|`hxZEIk;mm?WOncmJ0}efH3|~
z5?0aGy}bkX?c6co-M44Y{plfZXvfZhwEdCdK55Sv%U+{a$jki8f7A$%5&4C~F3|W_
z<P6;k{>@)L^0kULmM!P)4<r}<43f>~&3LigsG0Fbsa_OflP^A0%uC1J5A5GDxNn!<
z`u|BOZzuWOwV%ns at vJ-1Qui6I+3&08wzT^!yC>3oeJ*L4khbulpHCXI`!M_L(tO=d
zX=#5yu!o()u2c6ry3g7wF}ruseBIw at srw>*%4t6>KOy;cFQj$d4{4c_c6;dj(e>Xc
zZGR2r>wZp4_0#!v{r;fxCoM1Art|B5QOn1*qbsdJ_!yLmU6bbPept&{*Eu at B`hCjf
z?{xiiKdhzpv-$R1*RS!c#O#{%^IV at pT1LIJu4UQf>-z6<&#}c)+QWzDY3xgKV&~U<
zeZFgXN;|qz*RSEn<izIdeqNu)hg*XY-?NROqa}21Proj&aK7%p2Q~-!x{uei==#4I
z$=7|tn9J9F{A&5%j^rP8`{tuAKcR`PjIRHC5^t85-XFSOOSA>+k9uic%jYEbicr4p
z-`YQ7{*NTr+UxwfuS&W6r=7ok at 6vhoI({O#wu|QL at 42V057yr<ZQ(=nHFiQy!uh(t
zYTXj#NB_Uvax~q%7RlFrcEaT^c62Av`G5T(`O*H-`a6+)-LJO0`4etlEu#5<k_H=7
zKi$V?Tz>R=qxJVC*Tz!v3Llzp+rx+EYiW}M>2NP&`nLwrlv~*K(rmwj>-zQcXPxBh
h+QTDE+z{k%UYsasja1EsRq~&>G06XIBq35Y{{#`pM9BaE
literal 0
HcmV?d00001
>From 8e781d63321c194bbeed7c9b290513a639091385 Mon Sep 17 00:00:00 2001
From: Adam Kallai <kadam at inf.u-szeged.hu>
Date: Tue, 27 Jan 2026 09:56:02 +0100
Subject: [PATCH 7/7] Update PerfSpeEvent unittest
---
bolt/unittests/Profile/PerfSpeEvents.cpp | 30 +++++++++++++-----------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/bolt/unittests/Profile/PerfSpeEvents.cpp b/bolt/unittests/Profile/PerfSpeEvents.cpp
index 4f060cd0aa7c8..b736c38f691c8 100644
--- a/bolt/unittests/Profile/PerfSpeEvents.cpp
+++ b/bolt/unittests/Profile/PerfSpeEvents.cpp
@@ -22,7 +22,7 @@ using namespace llvm::object;
using namespace llvm::ELF;
namespace opts {
-extern cl::opt<std::string> ReadPerfEvents;
+extern cl::opt<bool> ReadPerfTextData;
extern cl::opt<bool> ArmSPE;
} // namespace opts
@@ -92,10 +92,10 @@ struct PerfSpeEventsTestHelper : public testing::Test {
/// Parse and check SPE brstack as LBR.
void parseAndCheckBrstackEvents(
- uint64_t PID,
+ uint64_t PID, StringRef &Buffer,
const std::vector<std::pair<Trace, TakenBranchInfo>> &ExpectedSamples) {
DataAggregator DA("<pseudo input>");
- DA.ParsingBuf = opts::ReadPerfEvents;
+ DA.ParsingBuf = Buffer;
DA.BC = BC.get();
DataAggregator::MMapInfo MMap;
DA.BinaryMMapInfo.insert(std::make_pair(PID, MMap));
@@ -134,14 +134,15 @@ TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstack) {
// ```
opts::ArmSPE = true;
- opts::ReadPerfEvents = " 1234 0xa001/0xa002/PN/-/-/10/COND/-\n"
- " 1234 0xb001/0xb002/P/-/-/4/RET/-\n"
- " 1234 0xc456/0xc789/P/-/-/13/-/-\n"
- " 1234 0xd123/0xd456/M/-/-/7/RET/-\n"
- " 1234 0xe001/0xe002/P/-/-/14/RET/-\n"
- " 1234 0xd123/0xd456/M/-/-/7/RET/-\n"
- " 1234 0xf001/0xf002/MN/-/-/8/COND/-\n"
- " 1234 0xc456/0xc789/M/-/-/13/-/-\n";
+ opts::ReadPerfTextData = true;
+ StringRef Buffer = " 1234 0xa001/0xa002/PN/-/-/10/COND/-\n"
+ " 1234 0xb001/0xb002/P/-/-/4/RET/-\n"
+ " 1234 0xc456/0xc789/P/-/-/13/-/-\n"
+ " 1234 0xd123/0xd456/M/-/-/7/RET/-\n"
+ " 1234 0xe001/0xe002/P/-/-/14/RET/-\n"
+ " 1234 0xd123/0xd456/M/-/-/7/RET/-\n"
+ " 1234 0xf001/0xf002/MN/-/-/8/COND/-\n"
+ " 1234 0xc456/0xc789/M/-/-/13/-/-\n";
// ExpectedSamples contains the aggregated information about
// a branch {{Branch From, To}, {TakenCount, MispredCount}}.
@@ -158,7 +159,7 @@ TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstack) {
{{0xe001, 0xe002, Trace::BR_ONLY}, {1, 0}},
{{0xf001, 0xf002, Trace::BR_ONLY}, {1, 1}}};
- parseAndCheckBrstackEvents(1234, ExpectedSamples);
+ parseAndCheckBrstackEvents(1234, Buffer, ExpectedSamples);
}
TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstackAndPbt) {
@@ -174,7 +175,8 @@ TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstackAndPbt) {
// ```
opts::ArmSPE = true;
- opts::ReadPerfEvents =
+ opts::ReadPerfTextData = true;
+ StringRef Buffer =
// "<PID> <SRC>/<DEST>/PN/-/-/10/COND/- <NULL>/<PBT>/-/-/-/0//-\n"
" 4567 0xa002/0xa003/PN/-/-/10/COND/- 0x0/0xa001/-/-/-/0//-\n"
" 4567 0xb002/0xb003/P/-/-/4/RET/- 0x0/0xb001/-/-/-/0//-\n"
@@ -246,7 +248,7 @@ TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstackAndPbt) {
{{0xf002, 0xf003, Trace::BR_ONLY}, {1, 1}},
{{0x0, 0xf001, 0xf002}, {1, 0}}};
- parseAndCheckBrstackEvents(4567, ExpectedSamples);
+ parseAndCheckBrstackEvents(4567, Buffer, ExpectedSamples);
}
#endif
More information about the llvm-commits
mailing list