Skip to content

Commit dadaa79

Browse files
authored
[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.
1 parent f5b6b89 commit dadaa79

File tree

1 file changed

+40
-19
lines changed

1 file changed

+40
-19
lines changed

bolt/runtime/instr.cpp

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -672,14 +672,15 @@ bool parseAddressRange(const char *Str, uint64_t &StartAddress,
672672
return true;
673673
}
674674

675+
static constexpr uint32_t NameMax = 4096;
676+
static char TargetPath[NameMax] = {};
677+
675678
/// Get full path to the real binary by getting current virtual address
676679
/// and searching for the appropriate link in address range in
677680
/// /proc/self/map_files
678681
static char *getBinaryPath() {
679682
const uint32_t BufSize = 1024;
680-
const uint32_t NameMax = 4096;
681683
const char DirPath[] = "/proc/self/map_files/";
682-
static char TargetPath[NameMax] = {};
683684
char Buf[BufSize];
684685

685686
if (__bolt_instr_binpath[0] != '\0')
@@ -719,22 +720,31 @@ static char *getBinaryPath() {
719720
return nullptr;
720721
}
721722

722-
ProfileWriterContext readDescriptions() {
723+
ProfileWriterContext readDescriptions(const uint8_t *BinContents,
724+
uint64_t Size) {
723725
ProfileWriterContext Result;
724-
const char *BinPath = getBinaryPath();
725-
assert(BinPath && BinPath[0] != '\0', "failed to find binary path");
726726

727-
uint64_t FD = __open(BinPath, O_RDONLY,
728-
/*mode=*/0666);
729-
assert(static_cast<int64_t>(FD) >= 0, "failed to open binary path");
727+
assert((BinContents == nullptr) == (Size == 0),
728+
"either empty or valid library content buffer");
729+
730+
if (BinContents) {
731+
Result.FileDesc = -1;
732+
} else {
733+
const char *BinPath = getBinaryPath();
734+
assert(BinPath && BinPath[0] != '\0', "failed to find binary path");
730735

731-
Result.FileDesc = FD;
736+
uint64_t FD = __open(BinPath, O_RDONLY,
737+
/*mode=*/0666);
738+
assert(static_cast<int64_t>(FD) >= 0, "failed to open binary path");
732739

733-
// mmap our binary to memory
734-
uint64_t Size = __lseek(FD, 0, SEEK_END);
735-
const uint8_t *BinContents = reinterpret_cast<uint8_t *>(
736-
__mmap(0, Size, PROT_READ, MAP_PRIVATE, FD, 0));
737-
assert(BinContents != MAP_FAILED, "readDescriptions: Failed to mmap self!");
740+
Result.FileDesc = FD;
741+
742+
// mmap our binary to memory
743+
Size = __lseek(FD, 0, SEEK_END);
744+
BinContents = reinterpret_cast<uint8_t *>(
745+
__mmap(0, Size, PROT_READ, MAP_PRIVATE, FD, 0));
746+
assert(BinContents != MAP_FAILED, "readDescriptions: Failed to mmap self!");
747+
}
738748
Result.MMapPtr = BinContents;
739749
Result.MMapSize = Size;
740750
const Elf64_Ehdr *Hdr = reinterpret_cast<const Elf64_Ehdr *>(BinContents);
@@ -1509,7 +1519,7 @@ extern "C" void __bolt_instr_clear_counters() {
15091519
}
15101520

15111521
/// This is the entry point for profile writing.
1512-
/// There are three ways of getting here:
1522+
/// There are four ways of getting here:
15131523
///
15141524
/// * Program execution ended, finalization methods are running and BOLT
15151525
/// hooked into FINI from your binary dynamic section;
@@ -1518,9 +1528,18 @@ extern "C" void __bolt_instr_clear_counters() {
15181528
/// * BOLT prints this function address so you can attach a debugger and
15191529
/// call this function directly to get your profile written to disk
15201530
/// on demand.
1531+
/// * Application can, at interesting runtime point, iterate through all
1532+
/// the loaded native libraries and for each call dlopen() and dlsym()
1533+
/// to get a pointer to this function and call through the acquired
1534+
/// function pointer to dump profile data.
15211535
///
15221536
extern "C" void __attribute((force_align_arg_pointer))
1523-
__bolt_instr_data_dump(int FD) {
1537+
__bolt_instr_data_dump(int FD, const char *LibPath = nullptr,
1538+
const uint8_t *LibContents = nullptr,
1539+
uint64_t LibSize = 0) {
1540+
if (LibPath)
1541+
strCopy(TargetPath, LibPath, NameMax);
1542+
15241543
// Already dumping
15251544
if (!GlobalWriteProfileMutex->acquire())
15261545
return;
@@ -1531,7 +1550,7 @@ __bolt_instr_data_dump(int FD) {
15311550
assert(ret == 0, "Failed to ftruncate!");
15321551
BumpPtrAllocator HashAlloc;
15331552
HashAlloc.setMaxSize(0x6400000);
1534-
ProfileWriterContext Ctx = readDescriptions();
1553+
ProfileWriterContext Ctx = readDescriptions(LibContents, LibSize);
15351554
Ctx.CallFlowTable = new (HashAlloc, 0) CallFlowHashTable(HashAlloc);
15361555

15371556
DEBUG(printStats(Ctx));
@@ -1551,8 +1570,10 @@ __bolt_instr_data_dump(int FD) {
15511570
Ctx.CallFlowTable->forEachElement(visitCallFlowEntry, FD, &Ctx);
15521571

15531572
__fsync(FD);
1554-
__munmap((void *)Ctx.MMapPtr, Ctx.MMapSize);
1555-
__close(Ctx.FileDesc);
1573+
if (Ctx.FileDesc != -1) {
1574+
__munmap((void *)Ctx.MMapPtr, Ctx.MMapSize);
1575+
__close(Ctx.FileDesc);
1576+
}
15561577
HashAlloc.destroy();
15571578
GlobalWriteProfileMutex->release();
15581579
DEBUG(report("Finished writing profile.\n"));

0 commit comments

Comments
 (0)