From dadaa7941dfd1355569d8bee5d8e199db93364f5 Mon Sep 17 00:00:00 2001 From: YongKang Zhu Date: Mon, 14 Jul 2025 13:06:16 -0700 Subject: [PATCH] [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. --- bolt/runtime/instr.cpp | 59 ++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/bolt/runtime/instr.cpp b/bolt/runtime/instr.cpp index 141171a981b3..a42750cef6b6 100644 --- a/bolt/runtime/instr.cpp +++ b/bolt/runtime/instr.cpp @@ -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(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( - __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(FD) >= 0, "failed to open binary path"); + + Result.FileDesc = FD; + + // mmap our binary to memory + Size = __lseek(FD, 0, SEEK_END); + BinContents = reinterpret_cast( + __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(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"));