mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 05:26:07 +00:00

Bolt currently links and initializes all LLVM targets. This substantially increases the binary size, and link time if LTO is used. Instead, only link the targets specified by BOLT_TARGETS_TO_BUILD. We also have to only initialize those targets, so generate a TargetConfig.def file with the necessary information. The way the initialization is done mirrors what llvm-exegesis does. This reduces llvm-bolt size from 137MB to 78MB for me.
147 lines
5.4 KiB
C++
147 lines
5.4 KiB
C++
//===- bolt/unittest/Core/MemoryMaps.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/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 "llvm/Testing/Support/Error.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::object;
|
|
using namespace llvm::ELF;
|
|
using namespace bolt;
|
|
|
|
namespace opts {
|
|
extern cl::opt<std::string> ReadPerfEvents;
|
|
} // namespace opts
|
|
|
|
namespace {
|
|
|
|
/// Perform checks on memory map events normally captured in perf. Tests use
|
|
/// the 'opts::ReadPerfEvents' flag to emulate these events, passing a custom
|
|
/// 'perf script' output to DataAggregator.
|
|
struct MemoryMapsTester : public testing::TestWithParam<Triple::ArchType> {
|
|
void SetUp() override {
|
|
initalizeLLVM();
|
|
prepareElf();
|
|
initializeBOLT();
|
|
}
|
|
|
|
protected:
|
|
void initalizeLLVM() {
|
|
#define BOLT_TARGET(target) \
|
|
LLVMInitialize##target##TargetInfo(); \
|
|
LLVMInitialize##target##TargetMC(); \
|
|
LLVMInitialize##target##AsmParser(); \
|
|
LLVMInitialize##target##Disassembler(); \
|
|
LLVMInitialize##target##Target(); \
|
|
LLVMInitialize##target##AsmPrinter();
|
|
|
|
#include "bolt/Core/TargetConfig.def"
|
|
}
|
|
|
|
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 = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
|
|
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, true,
|
|
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
|
|
ASSERT_FALSE(!BC);
|
|
}
|
|
|
|
char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
|
|
std::unique_ptr<ObjectFile> ObjFile;
|
|
std::unique_ptr<BinaryContext> BC;
|
|
};
|
|
} // namespace
|
|
|
|
#ifdef X86_AVAILABLE
|
|
|
|
INSTANTIATE_TEST_SUITE_P(X86, MemoryMapsTester,
|
|
::testing::Values(Triple::x86_64));
|
|
|
|
#endif
|
|
|
|
#ifdef AARCH64_AVAILABLE
|
|
|
|
INSTANTIATE_TEST_SUITE_P(AArch64, MemoryMapsTester,
|
|
::testing::Values(Triple::aarch64));
|
|
|
|
#endif
|
|
|
|
/// Check that the correct mmap size is computed when we have multiple text
|
|
/// segment mappings.
|
|
TEST_P(MemoryMapsTester, ParseMultipleSegments) {
|
|
const int Pid = 1234;
|
|
StringRef Filename = "BINARY";
|
|
opts::ReadPerfEvents = formatv(
|
|
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
|
|
"[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
|
|
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
|
|
"[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
|
|
Pid, Filename);
|
|
|
|
BC->SegmentMapInfo[0x11da000] =
|
|
SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
|
|
BC->SegmentMapInfo[0x31d0000] =
|
|
SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0000, 0x3000000, 0x200000, true};
|
|
|
|
DataAggregator DA("");
|
|
BC->setFilename(Filename);
|
|
Error Err = DA.preprocessProfile(*BC);
|
|
|
|
// Ignore errors from perf2bolt when parsing memory events later on.
|
|
ASSERT_THAT_ERROR(std::move(Err), Succeeded());
|
|
|
|
auto &BinaryMMapInfo = DA.getBinaryMMapInfo();
|
|
auto El = BinaryMMapInfo.find(Pid);
|
|
// Check that memory mapping is present and has the expected size.
|
|
ASSERT_NE(El, BinaryMMapInfo.end());
|
|
ASSERT_EQ(El->second.Size, static_cast<uint64_t>(0xb1d0000));
|
|
}
|
|
|
|
/// Check that DataAggregator aborts when pre-processing an input binary
|
|
/// with multiple text segments that have different base addresses.
|
|
TEST_P(MemoryMapsTester, MultipleSegmentsMismatchedBaseAddress) {
|
|
const int Pid = 1234;
|
|
StringRef Filename = "BINARY";
|
|
opts::ReadPerfEvents = formatv(
|
|
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
|
|
"[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
|
|
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
|
|
"[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
|
|
Pid, Filename);
|
|
|
|
BC->SegmentMapInfo[0x11da000] =
|
|
SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
|
|
// Using '0x31d0fff' FileOffset which triggers a different base address
|
|
// for this second text segment.
|
|
BC->SegmentMapInfo[0x31d0000] =
|
|
SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0fff, 0x3000000, 0x200000, true};
|
|
|
|
DataAggregator DA("");
|
|
BC->setFilename(Filename);
|
|
ASSERT_DEBUG_DEATH(
|
|
{ Error Err = DA.preprocessProfile(*BC); },
|
|
"Base address on multiple segment mappings should match");
|
|
}
|