brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.0 KiB · 4f060cd Raw
253 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifdef AARCH64_AVAILABLE10 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 opts28 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(ElfBuf, "\177ELF", 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(ObjectFile::createObjectFile(Source));61  }62 63  void initializeBOLT() {64    Relocation::Arch = ObjFile->makeTriple().getArch();65    BC = cantFail(BinaryContext::createBinaryContext(66        ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),67        ObjFile->getFileName(), nullptr, /*IsPIC*/ false,68        DWARFContext::create(*ObjFile), {llvm::outs(), 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(std::make_pair(PID, MMap));102 103    DA.parseBranchEvents();104 105    EXPECT_EQ(DA.Traces.size(), ExpectedSamples.size());106    if (DA.Traces.size() != ExpectedSamples.size())107      reportBrStackEventMismatch(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(TracesBegin, TracesEnd,113                        [&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 bolt123} // namespace llvm124 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' -- BINARY130  // ```131  // How Bolt extracts the branch events:132  // ```133  // perf script -F pid,brstack --itrace=bl134  // ```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 about147  // 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 for150  // (0xd123, 0xd456) in our input. It also has MispredsCount = 2,151  // as 'M' misprediction flag appears in both cases. BR_ONLY means152  // the trace only contains branch data.153  std::vector<std::pair<Trace, TakenBranchInfo>> ExpectedSamples = {154      {{0xa001, 0xa002, Trace::BR_ONLY}, {1, 0}},155      {{0xb001, 0xb002, Trace::BR_ONLY}, {1, 0}},156      {{0xc456, 0xc789, Trace::BR_ONLY}, {2, 1}},157      {{0xd123, 0xd456, Trace::BR_ONLY}, {2, 2}},158      {{0xe001, 0xe002, Trace::BR_ONLY}, {1, 0}},159      {{0xf001, 0xf002, Trace::BR_ONLY}, {1, 1}}};160 161  parseAndCheckBrstackEvents(1234, ExpectedSamples);162}163 164TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstackAndPbt) {165  // Check perf input with SPE branch events as brstack format by166  // combining with the previous branch target address (named as PBT).167  // Example collection command:168  // ```169  // perf record -e 'arm_spe_0/branch_filter=1/u' -- BINARY170  // ```171  // How Bolt extracts the branch events:172  // ```173  // perf script -F pid,brstack --itrace=bl174  // ```175 176  opts::ArmSPE = true;177  opts::ReadPerfEvents =178      // "<PID> <SRC>/<DEST>/PN/-/-/10/COND/- <NULL>/<PBT>/-/-/-/0//-\n"179      "  4567  0xa002/0xa003/PN/-/-/10/COND/- 0x0/0xa001/-/-/-/0//-\n"180      "  4567  0xb002/0xb003/P/-/-/4/RET/- 0x0/0xb001/-/-/-/0//-\n"181      "  4567  0xc456/0xc789/P/-/-/13/-/- 0x0/0xc123/-/-/-/0//-\n"182      "  4567  0xd456/0xd789/M/-/-/7/RET/- 0x0/0xd123/-/-/-/0//-\n"183      "  4567  0xe005/0xe009/P/-/-/14/RET/- 0x0/0xe001/-/-/-/0//-\n"184      "  4567  0xd456/0xd789/M/-/-/7/RET/- 0x0/0xd123/-/-/-/0//-\n"185      "  4567  0xf002/0xf003/MN/-/-/8/COND/- 0x0/0xf001/-/-/-/0//-\n"186      "  4567  0xc456/0xc789/P/-/-/13/-/- 0x0/0xc123/-/-/-/0//-\n";187 188  // ExpectedSamples contains the aggregated information about189  // a branch {{From, To, TraceTo}, {TakenCount, MispredCount}}.190  // Where191  // - From: is the source address of the sampled branch operation.192  // - To: is the target address of the sampled branch operation.193  // - TraceTo could be either194  //    - A 'Type = Trace::BR_ONLY', which means the trace only contains branch195  //    data.196  //    - Or an address, when the trace contains information about the previous197  //    branch.198  //199  // When FEAT_SPE_PBT is present, Arm SPE emits two records per sample:200  // - the current branch (Spe.From/Spe.To), and201  // - the previous taken branch target (PBT) (PBT.From, PBT.To).202  //203  // Together they behave like a depth-1 branch stack where:204  //   - the PBT entry is always taken205  //   - the current branch entry may represent a taken branch or a fall-through206  //   - the destination (Spe.To) is the architecturally executed target207  //208  // There can be fall-throughs to be inferred between the PBT entry and209  // the current branch (Spe.From), but there cannot be between current210  // branch's (Spe.From/Spe.To).211  //212  // PBT records only the target address (PBT.To), meaning we have no213  // information as the branch source (PBT.From=0x0), branch type, and the214  // prediction bit.215  //216  // Consider the trace pair:217  // {{Spe.From, Spe.To, Type}, {TK, MP}},218  //   {{PBT.From, PBT.To, TraceTo}, {TK, MP}}219  // {{0xd456, 0xd789, Trace::BR_ONLY}, {2, 2}}, {{0x0, 0xd123, 0xd456}, {2, 0}}220  //221  // The first entry is the Spe record, which represents a trace from 0xd456222  // (Spe.From) to 0xd789 (Spe.To). Type = Trace::BR_ONLY, as Bolt processes the223  // current branch event first. At this point we have no information about the224  // previous trace (PBT). This entry has a TakenCount = 2, as we have two225  // samples for (0xd456, 0xd789) in our input. It also has MispredsCount = 2,226  // as 'M' misprediction flag appears in both cases.227  //228  // The second entry is the PBT record. TakenCount = 2 because the229  // (PBT.From = 0x0, PBT.To = 0xd123) branch target appears twice in the input,230  // and MispredsCount = 0 because prediction data is absent. There is no branch231  // source information, so the PBT.From field is zero (0x0). TraceTo = 0xd456232  // connect the flow from the previous taken branch at 0xd123 (PBT.To) to the233  // current source branch at 0xd456 (Spe.From), which then continues to 0xd789234  // (Spe.To).235  std::vector<std::pair<Trace, TakenBranchInfo>> ExpectedSamples = {236      {{0xa002, 0xa003, Trace::BR_ONLY}, {1, 0}},237      {{0x0, 0xa001, 0xa002}, {1, 0}},238      {{0xb002, 0xb003, Trace::BR_ONLY}, {1, 0}},239      {{0x0, 0xb001, 0xb002}, {1, 0}},240      {{0xc456, 0xc789, Trace::BR_ONLY}, {2, 0}},241      {{0x0, 0xc123, 0xc456}, {2, 0}},242      {{0xd456, 0xd789, Trace::BR_ONLY}, {2, 2}},243      {{0x0, 0xd123, 0xd456}, {2, 0}},244      {{0xe005, 0xe009, Trace::BR_ONLY}, {1, 0}},245      {{0x0, 0xe001, 0xe005}, {1, 0}},246      {{0xf002, 0xf003, Trace::BR_ONLY}, {1, 1}},247      {{0x0, 0xf001, 0xf002}, {1, 0}}};248 249  parseAndCheckBrstackEvents(4567, ExpectedSamples);250}251 252#endif253