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
253 lines
10 KiB
C++
253 lines
10 KiB
C++
//===- bolt/unittests/Profile/PerfSpeEvents.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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifdef AARCH64_AVAILABLE
|
|
|
|
#include "bolt/Core/BinaryContext.h"
|
|
#include "bolt/Profile/DataAggregator.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;
|
|
using namespace llvm::object;
|
|
using namespace llvm::ELF;
|
|
|
|
namespace opts {
|
|
extern cl::opt<std::string> ReadPerfEvents;
|
|
extern cl::opt<bool> ArmSPE;
|
|
} // namespace opts
|
|
|
|
namespace llvm {
|
|
namespace bolt {
|
|
|
|
/// Perform checks on perf SPE branch events.
|
|
struct PerfSpeEventsTestHelper : public testing::Test {
|
|
void SetUp() override {
|
|
initalizeLLVM();
|
|
prepareElf();
|
|
initializeBOLT();
|
|
}
|
|
|
|
protected:
|
|
using Trace = DataAggregator::Trace;
|
|
using TakenBranchInfo = DataAggregator::TakenBranchInfo;
|
|
|
|
void initalizeLLVM() {
|
|
llvm::InitializeAllTargetInfos();
|
|
llvm::InitializeAllTargetMCs();
|
|
llvm::InitializeAllAsmParsers();
|
|
llvm::InitializeAllDisassemblers();
|
|
llvm::InitializeAllTargets();
|
|
llvm::InitializeAllAsmPrinters();
|
|
}
|
|
|
|
void prepareElf() {
|
|
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_AARCH64;
|
|
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
|
|
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
|
|
}
|
|
|
|
void initializeBOLT() {
|
|
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<ObjectFile> ObjFile;
|
|
std::unique_ptr<BinaryContext> BC;
|
|
|
|
/// Helper function to export lists to show the mismatch.
|
|
void reportBrStackEventMismatch(
|
|
const std::vector<std::pair<Trace, TakenBranchInfo>> &Traces,
|
|
const std::vector<std::pair<Trace, TakenBranchInfo>> &ExpectedSamples) {
|
|
llvm::errs() << "Traces items: \n";
|
|
for (const auto &[Trace, BI] : Traces)
|
|
llvm::errs() << "{" << Trace.Branch << ", " << Trace.From << ","
|
|
<< Trace.To << ", " << BI.TakenCount << ", "
|
|
<< BI.MispredCount << "}" << "\n";
|
|
|
|
llvm::errs() << "Expected items: \n";
|
|
for (const auto &[Trace, BI] : ExpectedSamples)
|
|
llvm::errs() << "{" << Trace.Branch << ", " << Trace.From << ", "
|
|
<< Trace.To << ", " << BI.TakenCount << ", "
|
|
<< BI.MispredCount << "}" << "\n";
|
|
}
|
|
|
|
/// Parse and check SPE brstack as LBR.
|
|
void parseAndCheckBrstackEvents(
|
|
uint64_t PID,
|
|
const std::vector<std::pair<Trace, TakenBranchInfo>> &ExpectedSamples) {
|
|
DataAggregator DA("<pseudo input>");
|
|
DA.ParsingBuf = opts::ReadPerfEvents;
|
|
DA.BC = BC.get();
|
|
DataAggregator::MMapInfo MMap;
|
|
DA.BinaryMMapInfo.insert(std::make_pair(PID, MMap));
|
|
|
|
DA.parseBranchEvents();
|
|
|
|
EXPECT_EQ(DA.Traces.size(), ExpectedSamples.size());
|
|
if (DA.Traces.size() != ExpectedSamples.size())
|
|
reportBrStackEventMismatch(DA.Traces, ExpectedSamples);
|
|
|
|
const auto TracesBegin = DA.Traces.begin();
|
|
const auto TracesEnd = DA.Traces.end();
|
|
for (const auto &BI : ExpectedSamples) {
|
|
auto it = find_if(TracesBegin, TracesEnd,
|
|
[&BI](const auto &Tr) { return Tr.first == BI.first; });
|
|
|
|
EXPECT_NE(it, TracesEnd);
|
|
EXPECT_EQ(it->second.MispredCount, BI.second.MispredCount);
|
|
EXPECT_EQ(it->second.TakenCount, BI.second.TakenCount);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace bolt
|
|
} // namespace llvm
|
|
|
|
TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstack) {
|
|
// Check perf input with SPE branch events as brstack format.
|
|
// Example collection command:
|
|
// ```
|
|
// perf record -e 'arm_spe_0/branch_filter=1/u' -- BINARY
|
|
// ```
|
|
// How Bolt extracts the branch events:
|
|
// ```
|
|
// perf script -F pid,brstack --itrace=bl
|
|
// ```
|
|
|
|
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";
|
|
|
|
// ExpectedSamples contains the aggregated information about
|
|
// a branch {{Branch From, To}, {TakenCount, MispredCount}}.
|
|
// Consider this example trace: {{0xd123, 0xd456, Trace::BR_ONLY},
|
|
// {2,2}}. This entry has a TakenCount = 2, as we have two samples for
|
|
// (0xd123, 0xd456) in our input. It also has MispredsCount = 2,
|
|
// as 'M' misprediction flag appears in both cases. BR_ONLY means
|
|
// the trace only contains branch data.
|
|
std::vector<std::pair<Trace, TakenBranchInfo>> ExpectedSamples = {
|
|
{{0xa001, 0xa002, Trace::BR_ONLY}, {1, 0}},
|
|
{{0xb001, 0xb002, Trace::BR_ONLY}, {1, 0}},
|
|
{{0xc456, 0xc789, Trace::BR_ONLY}, {2, 1}},
|
|
{{0xd123, 0xd456, Trace::BR_ONLY}, {2, 2}},
|
|
{{0xe001, 0xe002, Trace::BR_ONLY}, {1, 0}},
|
|
{{0xf001, 0xf002, Trace::BR_ONLY}, {1, 1}}};
|
|
|
|
parseAndCheckBrstackEvents(1234, ExpectedSamples);
|
|
}
|
|
|
|
TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstackAndPbt) {
|
|
// Check perf input with SPE branch events as brstack format by
|
|
// combining with the previous branch target address (named as PBT).
|
|
// Example collection command:
|
|
// ```
|
|
// perf record -e 'arm_spe_0/branch_filter=1/u' -- BINARY
|
|
// ```
|
|
// How Bolt extracts the branch events:
|
|
// ```
|
|
// perf script -F pid,brstack --itrace=bl
|
|
// ```
|
|
|
|
opts::ArmSPE = true;
|
|
opts::ReadPerfEvents =
|
|
// "<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"
|
|
" 4567 0xc456/0xc789/P/-/-/13/-/- 0x0/0xc123/-/-/-/0//-\n"
|
|
" 4567 0xd456/0xd789/M/-/-/7/RET/- 0x0/0xd123/-/-/-/0//-\n"
|
|
" 4567 0xe005/0xe009/P/-/-/14/RET/- 0x0/0xe001/-/-/-/0//-\n"
|
|
" 4567 0xd456/0xd789/M/-/-/7/RET/- 0x0/0xd123/-/-/-/0//-\n"
|
|
" 4567 0xf002/0xf003/MN/-/-/8/COND/- 0x0/0xf001/-/-/-/0//-\n"
|
|
" 4567 0xc456/0xc789/P/-/-/13/-/- 0x0/0xc123/-/-/-/0//-\n";
|
|
|
|
// ExpectedSamples contains the aggregated information about
|
|
// a branch {{From, To, TraceTo}, {TakenCount, MispredCount}}.
|
|
// Where
|
|
// - From: is the source address of the sampled branch operation.
|
|
// - To: is the target address of the sampled branch operation.
|
|
// - TraceTo could be either
|
|
// - A 'Type = Trace::BR_ONLY', which means the trace only contains branch
|
|
// data.
|
|
// - Or an address, when the trace contains information about the previous
|
|
// branch.
|
|
//
|
|
// When FEAT_SPE_PBT is present, Arm SPE emits two records per sample:
|
|
// - the current branch (Spe.From/Spe.To), and
|
|
// - the previous taken branch target (PBT) (PBT.From, PBT.To).
|
|
//
|
|
// Together they behave like a depth-1 branch stack where:
|
|
// - the PBT entry is always taken
|
|
// - the current branch entry may represent a taken branch or a fall-through
|
|
// - the destination (Spe.To) is the architecturally executed target
|
|
//
|
|
// There can be fall-throughs to be inferred between the PBT entry and
|
|
// the current branch (Spe.From), but there cannot be between current
|
|
// branch's (Spe.From/Spe.To).
|
|
//
|
|
// PBT records only the target address (PBT.To), meaning we have no
|
|
// information as the branch source (PBT.From=0x0), branch type, and the
|
|
// prediction bit.
|
|
//
|
|
// Consider the trace pair:
|
|
// {{Spe.From, Spe.To, Type}, {TK, MP}},
|
|
// {{PBT.From, PBT.To, TraceTo}, {TK, MP}}
|
|
// {{0xd456, 0xd789, Trace::BR_ONLY}, {2, 2}}, {{0x0, 0xd123, 0xd456}, {2, 0}}
|
|
//
|
|
// The first entry is the Spe record, which represents a trace from 0xd456
|
|
// (Spe.From) to 0xd789 (Spe.To). Type = Trace::BR_ONLY, as Bolt processes the
|
|
// current branch event first. At this point we have no information about the
|
|
// previous trace (PBT). This entry has a TakenCount = 2, as we have two
|
|
// samples for (0xd456, 0xd789) in our input. It also has MispredsCount = 2,
|
|
// as 'M' misprediction flag appears in both cases.
|
|
//
|
|
// The second entry is the PBT record. TakenCount = 2 because the
|
|
// (PBT.From = 0x0, PBT.To = 0xd123) branch target appears twice in the input,
|
|
// and MispredsCount = 0 because prediction data is absent. There is no branch
|
|
// source information, so the PBT.From field is zero (0x0). TraceTo = 0xd456
|
|
// connect the flow from the previous taken branch at 0xd123 (PBT.To) to the
|
|
// current source branch at 0xd456 (Spe.From), which then continues to 0xd789
|
|
// (Spe.To).
|
|
std::vector<std::pair<Trace, TakenBranchInfo>> ExpectedSamples = {
|
|
{{0xa002, 0xa003, Trace::BR_ONLY}, {1, 0}},
|
|
{{0x0, 0xa001, 0xa002}, {1, 0}},
|
|
{{0xb002, 0xb003, Trace::BR_ONLY}, {1, 0}},
|
|
{{0x0, 0xb001, 0xb002}, {1, 0}},
|
|
{{0xc456, 0xc789, Trace::BR_ONLY}, {2, 0}},
|
|
{{0x0, 0xc123, 0xc456}, {2, 0}},
|
|
{{0xd456, 0xd789, Trace::BR_ONLY}, {2, 2}},
|
|
{{0x0, 0xd123, 0xd456}, {2, 0}},
|
|
{{0xe005, 0xe009, Trace::BR_ONLY}, {1, 0}},
|
|
{{0x0, 0xe001, 0xe005}, {1, 0}},
|
|
{{0xf002, 0xf003, Trace::BR_ONLY}, {1, 1}},
|
|
{{0x0, 0xf001, 0xf002}, {1, 0}}};
|
|
|
|
parseAndCheckBrstackEvents(4567, ExpectedSamples);
|
|
}
|
|
|
|
#endif
|