1//===- bolt/unittests/Profile/PerfSpeEvents.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifdef AARCH64_AVAILABLE
10
11#include "bolt/Core/BinaryContext.h"
12#include "bolt/Profile/DataAggregator.h"
13#include "llvm/BinaryFormat/ELF.h"
14#include "llvm/DebugInfo/DWARF/DWARFContext.h"
15#include "llvm/Support/CommandLine.h"
16#include "llvm/Support/TargetSelect.h"
17#include "gtest/gtest.h"
18
19using namespace llvm;
20using namespace llvm::bolt;
21using namespace llvm::object;
22using namespace llvm::ELF;
23
24namespace opts {
25extern cl::opt<std::string> ReadPerfEvents;
26extern cl::opt<bool> ArmSPE;
27} // namespace opts
28
29namespace llvm {
30namespace bolt {
31
32/// Perform checks on perf SPE branch events.
33struct PerfSpeEventsTestHelper : public testing::Test {
34 void SetUp() override {
35 initalizeLLVM();
36 prepareElf();
37 initializeBOLT();
38 }
39
40protected:
41 using Trace = DataAggregator::Trace;
42 using TakenBranchInfo = DataAggregator::TakenBranchInfo;
43
44 void initalizeLLVM() {
45 llvm::InitializeAllTargetInfos();
46 llvm::InitializeAllTargetMCs();
47 llvm::InitializeAllAsmParsers();
48 llvm::InitializeAllDisassemblers();
49 llvm::InitializeAllTargets();
50 llvm::InitializeAllAsmPrinters();
51 }
52
53 void prepareElf() {
54 memcpy(dest: ElfBuf, src: "\177ELF", n: 4);
55 ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
56 EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
57 EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
58 EHdr->e_machine = llvm::ELF::EM_AARCH64;
59 MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
60 ObjFile = cantFail(ValOrErr: ObjectFile::createObjectFile(Object: Source));
61 }
62
63 void initializeBOLT() {
64 Relocation::Arch = ObjFile->makeTriple().getArch();
65 BC = cantFail(ValOrErr: BinaryContext::createBinaryContext(
66 TheTriple: ObjFile->makeTriple(), SSP: std::make_shared<orc::SymbolStringPool>(),
67 InputFileName: ObjFile->getFileName(), Features: nullptr, /*IsPIC*/ false,
68 DwCtx: DWARFContext::create(Obj: *ObjFile), Logger: {.Out: llvm::outs(), .Err: llvm::errs()}));
69 ASSERT_FALSE(!BC);
70 }
71
72 char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
73 std::unique_ptr<ObjectFile> ObjFile;
74 std::unique_ptr<BinaryContext> BC;
75
76 /// Helper function to export lists to show the mismatch.
77 void reportBrStackEventMismatch(
78 const std::vector<std::pair<Trace, TakenBranchInfo>> &Traces,
79 const std::vector<std::pair<Trace, TakenBranchInfo>> &ExpectedSamples) {
80 llvm::errs() << "Traces items: \n";
81 for (const auto &[Trace, BI] : Traces)
82 llvm::errs() << "{" << Trace.Branch << ", " << Trace.From << ","
83 << Trace.To << ", " << BI.TakenCount << ", "
84 << BI.MispredCount << "}" << "\n";
85
86 llvm::errs() << "Expected items: \n";
87 for (const auto &[Trace, BI] : ExpectedSamples)
88 llvm::errs() << "{" << Trace.Branch << ", " << Trace.From << ", "
89 << Trace.To << ", " << BI.TakenCount << ", "
90 << BI.MispredCount << "}" << "\n";
91 }
92
93 /// Parse and check SPE brstack as LBR.
94 void parseAndCheckBrstackEvents(
95 uint64_t PID,
96 const std::vector<std::pair<Trace, TakenBranchInfo>> &ExpectedSamples) {
97 DataAggregator DA("<pseudo input>");
98 DA.ParsingBuf = opts::ReadPerfEvents;
99 DA.BC = BC.get();
100 DataAggregator::MMapInfo MMap;
101 DA.BinaryMMapInfo.insert(x: std::make_pair(x&: PID, y&: MMap));
102
103 DA.parseBranchEvents();
104
105 EXPECT_EQ(DA.Traces.size(), ExpectedSamples.size());
106 if (DA.Traces.size() != ExpectedSamples.size())
107 reportBrStackEventMismatch(Traces: DA.Traces, ExpectedSamples);
108
109 const auto TracesBegin = DA.Traces.begin();
110 const auto TracesEnd = DA.Traces.end();
111 for (const auto &BI : ExpectedSamples) {
112 auto it = find_if(first: TracesBegin, last: TracesEnd,
113 pred: [&BI](const auto &Tr) { return Tr.first == BI.first; });
114
115 EXPECT_NE(it, TracesEnd);
116 EXPECT_EQ(it->second.MispredCount, BI.second.MispredCount);
117 EXPECT_EQ(it->second.TakenCount, BI.second.TakenCount);
118 }
119 }
120};
121
122} // namespace bolt
123} // namespace llvm
124
125TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstack) {
126 // Check perf input with SPE branch events as brstack format.
127 // Example collection command:
128 // ```
129 // perf record -e 'arm_spe_0/branch_filter=1/u' -- BINARY
130 // ```
131 // How Bolt extracts the branch events:
132 // ```
133 // perf script -F pid,brstack --itrace=bl
134 // ```
135
136 opts::ArmSPE = true;
137 opts::ReadPerfEvents = " 1234 0xa001/0xa002/PN/-/-/10/COND/-\n"
138 " 1234 0xb001/0xb002/P/-/-/4/RET/-\n"
139 " 1234 0xc456/0xc789/P/-/-/13/-/-\n"
140 " 1234 0xd123/0xd456/M/-/-/7/RET/-\n"
141 " 1234 0xe001/0xe002/P/-/-/14/RET/-\n"
142 " 1234 0xd123/0xd456/M/-/-/7/RET/-\n"
143 " 1234 0xf001/0xf002/MN/-/-/8/COND/-\n"
144 " 1234 0xc456/0xc789/M/-/-/13/-/-\n";
145
146 // ExpectedSamples contains the aggregated information about
147 // a branch {{Branch From, To}, {TakenCount, MispredCount}}.
148 // Consider this example trace: {{0xd123, 0xd456, Trace::BR_ONLY},
149 // {2,2}}. This entry has a TakenCount = 2, as we have two samples for
150 // (0xd123, 0xd456) in our input. It also has MispredsCount = 2,
151 // as 'M' misprediction flag appears in both cases. BR_ONLY means
152 // the trace only contains branch data.
153 std::vector<std::pair<Trace, TakenBranchInfo>> ExpectedSamples = {
154 {{.Branch: 0xa001, .From: 0xa002, .To: Trace::BR_ONLY}, {.TakenCount: 1, .MispredCount: 0}},
155 {{.Branch: 0xb001, .From: 0xb002, .To: Trace::BR_ONLY}, {.TakenCount: 1, .MispredCount: 0}},
156 {{.Branch: 0xc456, .From: 0xc789, .To: Trace::BR_ONLY}, {.TakenCount: 2, .MispredCount: 1}},
157 {{.Branch: 0xd123, .From: 0xd456, .To: Trace::BR_ONLY}, {.TakenCount: 2, .MispredCount: 2}},
158 {{.Branch: 0xe001, .From: 0xe002, .To: Trace::BR_ONLY}, {.TakenCount: 1, .MispredCount: 0}},
159 {{.Branch: 0xf001, .From: 0xf002, .To: Trace::BR_ONLY}, {.TakenCount: 1, .MispredCount: 1}}};
160
161 parseAndCheckBrstackEvents(PID: 1234, ExpectedSamples);
162}
163
164#endif
165

source code of bolt/unittests/Profile/PerfSpeEvents.cpp