[BOLT][instr] Add optional arguments to __bolt_instr_data_dump() (#148700)
`__bolt_instr_data_dump()` will find instrumented binary name by iterating through entries under directory `/proc/self/map_files`, and then open the binary and memory map it onto heap in order to locate `.bolt.instr.tables` section to read the descriptions. If binary name is already known and/or binary is already opened as memory mapped, we can pass binary name and/or memory buffer directly to `__bolt_instr_data_dump()` to save some work.
This commit is contained in:
parent
f5b6b896de
commit
dadaa7941d
@ -672,14 +672,15 @@ bool parseAddressRange(const char *Str, uint64_t &StartAddress,
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr uint32_t NameMax = 4096;
|
||||
static char TargetPath[NameMax] = {};
|
||||
|
||||
/// Get full path to the real binary by getting current virtual address
|
||||
/// and searching for the appropriate link in address range in
|
||||
/// /proc/self/map_files
|
||||
static char *getBinaryPath() {
|
||||
const uint32_t BufSize = 1024;
|
||||
const uint32_t NameMax = 4096;
|
||||
const char DirPath[] = "/proc/self/map_files/";
|
||||
static char TargetPath[NameMax] = {};
|
||||
char Buf[BufSize];
|
||||
|
||||
if (__bolt_instr_binpath[0] != '\0')
|
||||
@ -719,22 +720,31 @@ static char *getBinaryPath() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ProfileWriterContext readDescriptions() {
|
||||
ProfileWriterContext readDescriptions(const uint8_t *BinContents,
|
||||
uint64_t Size) {
|
||||
ProfileWriterContext Result;
|
||||
const char *BinPath = getBinaryPath();
|
||||
assert(BinPath && BinPath[0] != '\0', "failed to find binary path");
|
||||
|
||||
uint64_t FD = __open(BinPath, O_RDONLY,
|
||||
/*mode=*/0666);
|
||||
assert(static_cast<int64_t>(FD) >= 0, "failed to open binary path");
|
||||
assert((BinContents == nullptr) == (Size == 0),
|
||||
"either empty or valid library content buffer");
|
||||
|
||||
Result.FileDesc = FD;
|
||||
if (BinContents) {
|
||||
Result.FileDesc = -1;
|
||||
} else {
|
||||
const char *BinPath = getBinaryPath();
|
||||
assert(BinPath && BinPath[0] != '\0', "failed to find binary path");
|
||||
|
||||
// mmap our binary to memory
|
||||
uint64_t Size = __lseek(FD, 0, SEEK_END);
|
||||
const uint8_t *BinContents = reinterpret_cast<uint8_t *>(
|
||||
__mmap(0, Size, PROT_READ, MAP_PRIVATE, FD, 0));
|
||||
assert(BinContents != MAP_FAILED, "readDescriptions: Failed to mmap self!");
|
||||
uint64_t FD = __open(BinPath, O_RDONLY,
|
||||
/*mode=*/0666);
|
||||
assert(static_cast<int64_t>(FD) >= 0, "failed to open binary path");
|
||||
|
||||
Result.FileDesc = FD;
|
||||
|
||||
// mmap our binary to memory
|
||||
Size = __lseek(FD, 0, SEEK_END);
|
||||
BinContents = reinterpret_cast<uint8_t *>(
|
||||
__mmap(0, Size, PROT_READ, MAP_PRIVATE, FD, 0));
|
||||
assert(BinContents != MAP_FAILED, "readDescriptions: Failed to mmap self!");
|
||||
}
|
||||
Result.MMapPtr = BinContents;
|
||||
Result.MMapSize = Size;
|
||||
const Elf64_Ehdr *Hdr = reinterpret_cast<const Elf64_Ehdr *>(BinContents);
|
||||
@ -1509,7 +1519,7 @@ extern "C" void __bolt_instr_clear_counters() {
|
||||
}
|
||||
|
||||
/// This is the entry point for profile writing.
|
||||
/// There are three ways of getting here:
|
||||
/// There are four ways of getting here:
|
||||
///
|
||||
/// * Program execution ended, finalization methods are running and BOLT
|
||||
/// hooked into FINI from your binary dynamic section;
|
||||
@ -1518,9 +1528,18 @@ extern "C" void __bolt_instr_clear_counters() {
|
||||
/// * BOLT prints this function address so you can attach a debugger and
|
||||
/// call this function directly to get your profile written to disk
|
||||
/// on demand.
|
||||
/// * Application can, at interesting runtime point, iterate through all
|
||||
/// the loaded native libraries and for each call dlopen() and dlsym()
|
||||
/// to get a pointer to this function and call through the acquired
|
||||
/// function pointer to dump profile data.
|
||||
///
|
||||
extern "C" void __attribute((force_align_arg_pointer))
|
||||
__bolt_instr_data_dump(int FD) {
|
||||
__bolt_instr_data_dump(int FD, const char *LibPath = nullptr,
|
||||
const uint8_t *LibContents = nullptr,
|
||||
uint64_t LibSize = 0) {
|
||||
if (LibPath)
|
||||
strCopy(TargetPath, LibPath, NameMax);
|
||||
|
||||
// Already dumping
|
||||
if (!GlobalWriteProfileMutex->acquire())
|
||||
return;
|
||||
@ -1531,7 +1550,7 @@ __bolt_instr_data_dump(int FD) {
|
||||
assert(ret == 0, "Failed to ftruncate!");
|
||||
BumpPtrAllocator HashAlloc;
|
||||
HashAlloc.setMaxSize(0x6400000);
|
||||
ProfileWriterContext Ctx = readDescriptions();
|
||||
ProfileWriterContext Ctx = readDescriptions(LibContents, LibSize);
|
||||
Ctx.CallFlowTable = new (HashAlloc, 0) CallFlowHashTable(HashAlloc);
|
||||
|
||||
DEBUG(printStats(Ctx));
|
||||
@ -1551,8 +1570,10 @@ __bolt_instr_data_dump(int FD) {
|
||||
Ctx.CallFlowTable->forEachElement(visitCallFlowEntry, FD, &Ctx);
|
||||
|
||||
__fsync(FD);
|
||||
__munmap((void *)Ctx.MMapPtr, Ctx.MMapSize);
|
||||
__close(Ctx.FileDesc);
|
||||
if (Ctx.FileDesc != -1) {
|
||||
__munmap((void *)Ctx.MMapPtr, Ctx.MMapSize);
|
||||
__close(Ctx.FileDesc);
|
||||
}
|
||||
HashAlloc.destroy();
|
||||
GlobalWriteProfileMutex->release();
|
||||
DEBUG(report("Finished writing profile.\n"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user