Skip to content

Commit 505e186

Browse files
BOLT fails to read correctly the size of multi-segment mmaps.
1 parent 4dda564 commit 505e186

File tree

4 files changed

+134
-0
lines changed

4 files changed

+134
-0
lines changed

bolt/include/bolt/Profile/DataAggregator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,11 @@ class DataAggregator : public DataReader {
492492
/// and return a file name matching a given \p FileBuildID.
493493
std::optional<StringRef> getFileNameForBuildID(StringRef FileBuildID);
494494

495+
/// Get a constant reference to the parsed binary mmap entries.
496+
const std::unordered_map<uint64_t, MMapInfo> &getBinaryMMapInfo() {
497+
return BinaryMMapInfo;
498+
}
499+
495500
friend class YAMLProfileWriter;
496501
};
497502
} // namespace bolt

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ cl::opt<bool> ReadPreAggregated(
9595
"pa", cl::desc("skip perf and read data from a pre-aggregated file format"),
9696
cl::cat(AggregatorCategory));
9797

98+
cl::opt<std::string>
99+
ReadPerfEvents("perf-script-events",
100+
cl::desc("skip perf event collection by supplying a "
101+
"perf-script output in a textual format"),
102+
cl::cat(AggregatorCategory));
103+
98104
static cl::opt<bool>
99105
TimeAggregator("time-aggr",
100106
cl::desc("time BOLT aggregator"),
@@ -464,6 +470,13 @@ void DataAggregator::filterBinaryMMapInfo() {
464470

465471
int DataAggregator::prepareToParse(StringRef Name, PerfProcessInfo &Process,
466472
PerfProcessErrorCallbackTy Callback) {
473+
if (!opts::ReadPerfEvents.empty()) {
474+
dbgs() << "PERF2BOLT: using pre-processed perf events for '" << Name
475+
<< "' (perf-script-events)\n";
476+
ParsingBuf = opts::ReadPerfEvents;
477+
return 0;
478+
}
479+
467480
std::string Error;
468481
outs() << "PERF2BOLT: waiting for perf " << Name
469482
<< " collection to finish...\n";

bolt/unittests/Core/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS
88
add_bolt_unittest(CoreTests
99
BinaryContext.cpp
1010
MCPlusBuilder.cpp
11+
MemoryMaps.cpp
1112
DynoStats.cpp
1213

1314
DISABLE_LLVM_LINK_LLVM_DYLIB
@@ -17,6 +18,8 @@ target_link_libraries(CoreTests
1718
PRIVATE
1819
LLVMBOLTCore
1920
LLVMBOLTRewrite
21+
LLVMBOLTProfile
22+
LLVMTestingSupport
2023
)
2124

2225
foreach (tgt ${BOLT_TARGETS_TO_BUILD})

bolt/unittests/Core/MemoryMaps.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//===- bolt/unittest/Core/MemoryMaps.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+
#include "bolt/Core/BinaryContext.h"
10+
#include "bolt/Profile/DataAggregator.h"
11+
#include "llvm/BinaryFormat/ELF.h"
12+
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
13+
#include "llvm/Support/CommandLine.h"
14+
#include "llvm/Support/TargetSelect.h"
15+
#include "llvm/Testing/Support/Error.h"
16+
#include "gtest/gtest.h"
17+
18+
using namespace llvm;
19+
using namespace llvm::object;
20+
using namespace llvm::ELF;
21+
using namespace bolt;
22+
23+
namespace opts {
24+
extern cl::opt<std::string> ReadPerfEvents;
25+
} // namespace opts
26+
27+
namespace {
28+
struct MemoryMapsTester : public testing::TestWithParam<Triple::ArchType> {
29+
void SetUp() override {
30+
initalizeLLVM();
31+
prepareElf();
32+
initializeBOLT();
33+
}
34+
35+
protected:
36+
void initalizeLLVM() {
37+
llvm::InitializeAllTargetInfos();
38+
llvm::InitializeAllTargetMCs();
39+
llvm::InitializeAllAsmParsers();
40+
llvm::InitializeAllDisassemblers();
41+
llvm::InitializeAllTargets();
42+
llvm::InitializeAllAsmPrinters();
43+
}
44+
45+
void prepareElf() {
46+
memcpy(ElfBuf, "\177ELF", 4);
47+
ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
48+
EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
49+
EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
50+
EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
51+
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
52+
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
53+
}
54+
55+
void initializeBOLT() {
56+
Relocation::Arch = ObjFile->makeTriple().getArch();
57+
BC = cantFail(BinaryContext::createBinaryContext(
58+
ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
59+
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
60+
ASSERT_FALSE(!BC);
61+
}
62+
63+
char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
64+
std::unique_ptr<ObjectFile> ObjFile;
65+
std::unique_ptr<BinaryContext> BC;
66+
};
67+
} // namespace
68+
69+
#ifdef X86_AVAILABLE
70+
71+
INSTANTIATE_TEST_SUITE_P(X86, MemoryMapsTester,
72+
::testing::Values(Triple::x86_64));
73+
74+
#endif
75+
76+
#ifdef AARCH64_AVAILABLE
77+
78+
INSTANTIATE_TEST_SUITE_P(AArch64, MemoryMapsTester,
79+
::testing::Values(Triple::aarch64));
80+
81+
#endif
82+
83+
/// Check that the correct mmap size is computed when we have multiple text
84+
/// segment mappings. Uses 'opts::ReadPerfEvents' flag to pass a custom 'perf
85+
/// script' output, along with two text segments (SegmentInfo).
86+
TEST_P(MemoryMapsTester, ParseMultipleSegments) {
87+
const int Pid = 1234;
88+
StringRef Filename = "BINARY";
89+
opts::ReadPerfEvents = formatv(
90+
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
91+
"[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
92+
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
93+
"[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
94+
Pid, Filename);
95+
96+
BC->SegmentMapInfo[0x11da000] =
97+
SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000};
98+
BC->SegmentMapInfo[0x31d0000] =
99+
SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0000, 0x3000000, 0x200000};
100+
101+
DataAggregator DA("");
102+
BC->setFilename(Filename);
103+
Error Err = DA.preprocessProfile(*BC);
104+
105+
// Ignore errors from perf2bolt when parsing memory events later on.
106+
ASSERT_THAT_ERROR(std::move(Err), Succeeded());
107+
108+
auto &BinaryMMapInfo = DA.getBinaryMMapInfo();
109+
auto El = BinaryMMapInfo.find(Pid);
110+
// Check that memory mapping is present and has the expected size.
111+
ASSERT_NE(El, BinaryMMapInfo.end());
112+
ASSERT_EQ(El->second.Size, static_cast<uint64_t>(0xb1d0000));
113+
}

0 commit comments

Comments
 (0)