[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