CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
291 lines
10 KiB
C++
291 lines
10 KiB
C++
//===- bolt/unittests/Profile/DataAggregator.cpp --------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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;
|
|
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) {
|
|
opts::ReadPreAggregated = true;
|
|
|
|
DataAggregator DA("<pseudo input>");
|
|
std::optional<StringRef> FileName;
|
|
|
|
DA.setParsingBuffer("");
|
|
ASSERT_FALSE(DA.hasAllBuildIDs());
|
|
FileName = DA.getFileNameForBuildID("1234");
|
|
ASSERT_FALSE(FileName);
|
|
|
|
StringRef PartialValidBuildIDs = " File0\n"
|
|
"1111 File1\n"
|
|
" File2\n";
|
|
DA.setParsingBuffer(PartialValidBuildIDs);
|
|
ASSERT_FALSE(DA.hasAllBuildIDs());
|
|
FileName = DA.getFileNameForBuildID("0000");
|
|
ASSERT_FALSE(FileName);
|
|
FileName = DA.getFileNameForBuildID("1111");
|
|
ASSERT_EQ(*FileName, "File1");
|
|
|
|
StringRef AllValidBuildIDs = "0000 File0\n"
|
|
"1111 File1\n"
|
|
"2222 File2\n"
|
|
"333 File3\n";
|
|
DA.setParsingBuffer(AllValidBuildIDs);
|
|
ASSERT_TRUE(DA.hasAllBuildIDs());
|
|
FileName = DA.getFileNameForBuildID("1234");
|
|
ASSERT_FALSE(FileName);
|
|
FileName = DA.getFileNameForBuildID("2222");
|
|
ASSERT_EQ(*FileName, "File2");
|
|
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);
|
|
|
|
// -1 → UINT64_MAX (BR_ONLY / FT_ONLY).
|
|
Res = parseHex("-1\n");
|
|
ASSERT_TRUE(!!Res);
|
|
EXPECT_EQ(*Res, Trace::BR_ONLY);
|
|
|
|
// -2 → UINT64_MAX - 1 (FT_EXTERNAL_ORIGIN).
|
|
Res = parseHex("-2\n");
|
|
ASSERT_TRUE(!!Res);
|
|
EXPECT_EQ(*Res, Trace::FT_EXTERNAL_ORIGIN);
|
|
|
|
// -3 → UINT64_MAX - 2 (FT_EXTERNAL_RETURN).
|
|
Res = parseHex("-3\n");
|
|
ASSERT_TRUE(!!Res);
|
|
EXPECT_EQ(*Res, Trace::FT_EXTERNAL_RETURN);
|
|
|
|
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 3\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, 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, TraceWithNeg1AsBROnly) {
|
|
// T entry with -1 as fall-through target: parsed as BR_ONLY.
|
|
std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
|
|
parseAndCollectTraces("T 4b196f 4b19e0 -1 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, Trace::BR_ONLY);
|
|
EXPECT_EQ(Traces[0].second.TakenCount, 2u);
|
|
}
|
|
|
|
TEST_F(PreAggregatedX86TestHelper, TraceWithFFFAsBROnly) {
|
|
std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
|
|
parseAndCollectTraces("T 4b196f 4b19e0 ffffffffffffffff 2\n", Traces);
|
|
ASSERT_EQ(Traces.size(), 1u);
|
|
EXPECT_EQ(Traces[0].first.To, Trace::BR_ONLY);
|
|
}
|
|
|
|
TEST_F(PreAggregatedX86TestHelper, TraceWithBuildIdNeg1) {
|
|
std::vector<std::pair<Trace, TakenBranchInfo>> Traces;
|
|
parseAndCollectTraces("T 4b196f 4b19e0 deadbeef:-1 2\n", Traces);
|
|
ASSERT_EQ(Traces.size(), 1u);
|
|
EXPECT_EQ(Traces[0].first.To, Trace::BR_ONLY);
|
|
}
|
|
|
|
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
|