[llvm] [BOLT][instr] Add optional arguments to __bolt_instr_data_dump() (PR #148700)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 14 11:58:10 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-bolt

Author: YongKang Zhu (yozhu)

<details>
<summary>Changes</summary>

`__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.

---
Full diff: https://github.com/llvm/llvm-project/pull/148700.diff


1 Files Affected:

- (modified) bolt/runtime/instr.cpp (+40-19) 


``````````diff
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"));

``````````

</details>


https://github.com/llvm/llvm-project/pull/148700


More information about the llvm-commits mailing list