[llvm] [BOLT][instr] Add optional arguments to __bolt_instr_data_dump() (PR #148700)
YongKang Zhu via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 14 11:57:42 PDT 2025
https://github.com/yozhu created https://github.com/llvm/llvm-project/pull/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.
>From 59b144ef0a80ab8902c7e56d554647eaf46a05fa Mon Sep 17 00:00:00 2001
From: YongKang Zhu <yongzhu at fb.com>
Date: Fri, 11 Jul 2025 16:43:06 -0700
Subject: [PATCH] [BOLT][instr] Add optional arguments to
__bolt_instr_data_dump()
`__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 141171a981b39..a42750cef6b6e 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<int64_t>(FD) >= 0, "failed to open binary path");
+ assert((BinContents == nullptr) == (Size == 0),
+ "either empty or valid library content buffer");
+
+ if (BinContents) {
+ Result.FileDesc = -1;
+ } else {
+ const char *BinPath = getBinaryPath();
+ assert(BinPath && BinPath[0] != '\0', "failed to find binary path");
- Result.FileDesc = FD;
+ uint64_t FD = __open(BinPath, O_RDONLY,
+ /*mode=*/0666);
+ assert(static_cast<int64_t>(FD) >= 0, "failed to open 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!");
+ 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"));
More information about the llvm-commits
mailing list