[llvm] [BOLT] Add unit tests for pre-aggregated profile parsing (PR #192390)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 15 21:46:48 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-bolt
Author: Amir Ayupov (aaupov)
<details>
<summary>Changes</summary>
Add PreAggregatedTestHelper fixture with friend access to DataAggregator
internals. Add tests for parseHexField and all pre-aggregated entry
types (B, F, f, r, T, R).
---
Full diff: https://github.com/llvm/llvm-project/pull/192390.diff
2 Files Affected:
- (modified) bolt/include/bolt/Profile/DataAggregator.h (+1)
- (modified) bolt/unittests/Profile/DataAggregator.cpp (+208-2)
``````````diff
diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 6806854ad16d4..f7c9e31915d74 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -87,6 +87,7 @@ class DataAggregator : public DataReader {
friend raw_ostream &operator<<(raw_ostream &OS, const LBREntry &);
friend struct PerfSpeEventsTestHelper;
+ friend struct PreAggregatedTestHelper;
struct PerfBranchSample {
SmallVector<LBREntry, 32> LBR;
diff --git a/bolt/unittests/Profile/DataAggregator.cpp b/bolt/unittests/Profile/DataAggregator.cpp
index a27dd82de68e1..8e23b17d9f26c 100644
--- a/bolt/unittests/Profile/DataAggregator.cpp
+++ b/bolt/unittests/Profile/DataAggregator.cpp
@@ -7,7 +7,11 @@
//===----------------------------------------------------------------------===//
#include "bolt/Profile/DataAggregator.h"
+#include "bolt/Core/BinaryContext.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/TargetSelect.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -15,10 +19,75 @@ using namespace llvm::bolt;
namespace opts {
extern cl::opt<bool> ReadPreAggregated;
-}
+} // namespace opts
+
+namespace llvm {
+namespace bolt {
+
+/// Test helper with friend access to DataAggregator internals.
+/// Used for both parseHexField tests (no BC needed) and pre-aggregated
+/// parsing tests (BC needed, X86-only).
+struct PreAggregatedTestHelper : public testing::Test {
+ void SetUp() override { opts::ReadPreAggregated = true; }
+
+protected:
+ using Trace = DataAggregator::Trace;
+ using TakenBranchInfo = DataAggregator::TakenBranchInfo;
+
+ /// Parse a hex field from input string.
+ ErrorOr<uint64_t> parseHex(StringRef Input) {
+ DataAggregator DA("<pseudo input>");
+ DA.setParsingBuffer(Input);
+ return DA.parseHexField(' ', /*EndNl=*/true);
+ }
+
+ /// Parse pre-aggregated input and return collected Traces.
+ /// Requires BC to be initialized (X86-only tests).
+ void parseAndCollectTraces(
+ StringRef Input,
+ std::vector<std::pair<Trace, TakenBranchInfo>> &Result) {
+ DataAggregator DA("<pseudo input>");
+ DA.BC = BC.get();
+ DA.setParsingBuffer(Input);
+ std::error_code EC = DA.parsePreAggregatedLBRSamples();
+ ASSERT_FALSE(EC);
+ Result = std::move(DA.Traces);
+ }
+
+ /// Initialize target and BinaryContext for pre-aggregated tests.
+ void initializeBOLTForX86() {
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+ llvm::InitializeAllDisassemblers();
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+
+ memcpy(ElfBuf, "\177ELF", 4);
+ ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
+ EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
+ EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
+ EHdr->e_machine = llvm::ELF::EM_X86_64;
+ MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
+ ObjFile = cantFail(ObjectFile::createObjectFile(Source));
+
+ Relocation::Arch = ObjFile->makeTriple().getArch();
+ BC = cantFail(BinaryContext::createBinaryContext(
+ ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
+ ObjFile->getFileName(), nullptr, /*IsPIC*/ false,
+ DWARFContext::create(*ObjFile), {llvm::outs(), llvm::errs()}));
+ ASSERT_FALSE(!BC);
+ }
+
+ char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
+ std::unique_ptr<object::ObjectFile> ObjFile;
+ std::unique_ptr<BinaryContext> BC;
+};
+
+} // namespace bolt
+} // namespace llvm
TEST(DataAggregatorTest, buildID) {
- // Avoid looking for perf tool.
opts::ReadPreAggregated = true;
DataAggregator DA("<pseudo input>");
@@ -52,3 +121,140 @@ TEST(DataAggregatorTest, buildID) {
FileName = DA.getFileNameForBuildID("333");
ASSERT_EQ(*FileName, "File3");
}
+
+TEST_F(PreAggregatedTestHelper, parseHexField) {
+ auto Res = parseHex("4b196f\n");
+ ASSERT_TRUE(!!Res);
+ EXPECT_EQ(*Res, 0x4b196fULL);
+
+ Res = parseHex("ffffffffffffffff\n");
+ ASSERT_TRUE(!!Res);
+ EXPECT_EQ(*Res, Trace::BR_ONLY);
+
+ Res = parseHex("0\n");
+ ASSERT_TRUE(!!Res);
+ EXPECT_EQ(*Res, 0ULL);
+}
+
+#ifdef X86_AVAILABLE
+
+namespace llvm {
+namespace bolt {
+
+/// Fixture that adds X86 BinaryContext initialization on top of
+/// PreAggregatedTestHelper.
+struct PreAggregatedX86TestHelper : PreAggregatedTestHelper {
+ void SetUp() override {
+ PreAggregatedTestHelper::SetUp();
+ initializeBOLTForX86();
+ }
+};
+
+} // namespace bolt
+} // namespace llvm
+
+TEST_F(PreAggregatedX86TestHelper, BranchEntry) {
+ // B <from> <to> <count> <mispred>
+ // Trace: {from, to, BR_ONLY}
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("B 4b196f 4b19e0 2 0\n", Traces);
+ ASSERT_EQ(Traces.size(), 1u);
+ EXPECT_EQ(Traces[0].first.Branch, 0x4b196fULL);
+ EXPECT_EQ(Traces[0].first.From, 0x4b19e0ULL);
+ EXPECT_EQ(Traces[0].first.To, Trace::BR_ONLY);
+ EXPECT_EQ(Traces[0].second.TakenCount, 2u);
+ EXPECT_EQ(Traces[0].second.MispredCount, 0u);
+}
+
+TEST_F(PreAggregatedX86TestHelper, BranchWithMispreds) {
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("B 4b196f 4b19e0 10 3\n", Traces);
+ ASSERT_EQ(Traces.size(), 1u);
+ EXPECT_EQ(Traces[0].first.To, Trace::BR_ONLY);
+ EXPECT_EQ(Traces[0].second.TakenCount, 10u);
+ EXPECT_EQ(Traces[0].second.MispredCount, 3u);
+}
+
+TEST_F(PreAggregatedX86TestHelper, FallThrough) {
+ // F <from> <to> <count>
+ // Trace: {FT_ONLY, from, to}
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("F 4b196f 4b19e0 5\n", Traces);
+ ASSERT_EQ(Traces.size(), 1u);
+ EXPECT_EQ(Traces[0].first.Branch, Trace::FT_ONLY);
+ EXPECT_EQ(Traces[0].first.From, 0x4b196fULL);
+ EXPECT_EQ(Traces[0].first.To, 0x4b19e0ULL);
+ EXPECT_EQ(Traces[0].second.TakenCount, 5u);
+}
+
+TEST_F(PreAggregatedX86TestHelper, FallThroughExternalOrigin) {
+ // f <from> <to> <count>
+ // Trace: {FT_EXTERNAL_ORIGIN, from, to}
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("f 4b196f 4b19e0 3\n", Traces);
+ ASSERT_EQ(Traces.size(), 1u);
+ EXPECT_EQ(Traces[0].first.Branch, Trace::FT_EXTERNAL_ORIGIN);
+ EXPECT_EQ(Traces[0].first.From, 0x4b196fULL);
+ EXPECT_EQ(Traces[0].first.To, 0x4b19e0ULL);
+ EXPECT_EQ(Traces[0].second.TakenCount, 3u);
+}
+
+TEST_F(PreAggregatedX86TestHelper, FallThroughExternalReturn) {
+ // r <from> <to> <count>
+ // Trace: {FT_EXTERNAL_RETURN, from, to}
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("r 4b196f 4b19e0 7\n", Traces);
+ ASSERT_EQ(Traces.size(), 1u);
+ EXPECT_EQ(Traces[0].first.Branch, Trace::FT_EXTERNAL_RETURN);
+ EXPECT_EQ(Traces[0].first.From, 0x4b196fULL);
+ EXPECT_EQ(Traces[0].first.To, 0x4b19e0ULL);
+ EXPECT_EQ(Traces[0].second.TakenCount, 7u);
+}
+
+TEST_F(PreAggregatedX86TestHelper, TraceEntry) {
+ // T <branch> <from> <to> <count>
+ // Trace: {branch, from, to}
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("T 4b196f 4b19e0 4b19ef 2\n", Traces);
+ ASSERT_EQ(Traces.size(), 1u);
+ EXPECT_EQ(Traces[0].first.Branch, 0x4b196fULL);
+ EXPECT_EQ(Traces[0].first.From, 0x4b19e0ULL);
+ EXPECT_EQ(Traces[0].first.To, 0x4b19efULL);
+ EXPECT_EQ(Traces[0].second.TakenCount, 2u);
+}
+
+TEST_F(PreAggregatedX86TestHelper, ReturnEntry) {
+ // R <branch> <from> <to> <count>
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("R 4b196f 4b19e0 4b19ef 4\n", Traces);
+ ASSERT_EQ(Traces.size(), 1u);
+ EXPECT_EQ(Traces[0].first.Branch, 0x4b196fULL);
+ EXPECT_EQ(Traces[0].first.From, 0x4b19e0ULL);
+ EXPECT_EQ(Traces[0].first.To, 0x4b19efULL);
+ EXPECT_EQ(Traces[0].second.TakenCount, 4u);
+}
+
+TEST_F(PreAggregatedX86TestHelper, MultipleEntries) {
+ std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
+ parseAndCollectTraces("B 100 200 1 0\n"
+ "F 300 400 2\n"
+ "f 500 600 3\n"
+ "r 700 800 4\n"
+ "T 900 a00 b00 5\n",
+ Traces);
+ ASSERT_EQ(Traces.size(), 5u);
+ EXPECT_EQ(Traces[0].first.To, Trace::BR_ONLY);
+ EXPECT_EQ(Traces[0].second.TakenCount, 1u);
+ EXPECT_EQ(Traces[1].first.Branch, Trace::FT_ONLY);
+ EXPECT_EQ(Traces[1].second.TakenCount, 2u);
+ EXPECT_EQ(Traces[2].first.Branch, Trace::FT_EXTERNAL_ORIGIN);
+ EXPECT_EQ(Traces[2].second.TakenCount, 3u);
+ EXPECT_EQ(Traces[3].first.Branch, Trace::FT_EXTERNAL_RETURN);
+ EXPECT_EQ(Traces[3].second.TakenCount, 4u);
+ EXPECT_EQ(Traces[4].first.Branch, 0x900ULL);
+ EXPECT_EQ(Traces[4].first.From, 0xa00ULL);
+ EXPECT_EQ(Traces[4].first.To, 0xb00ULL);
+ EXPECT_EQ(Traces[4].second.TakenCount, 5u);
+}
+
+#endif
``````````
</details>
https://github.com/llvm/llvm-project/pull/192390
More information about the llvm-commits
mailing list