[llvm] [PseudoProbe] Support loading pseudo probe from debug binary (PR #175698)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 12 18:18:00 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-pgo
Author: Haohai Wen (HaohaiWen)
<details>
<summary>Changes</summary>
Pseudo probe and DWARF sections can occupy a significant amount of space
in binary for large application. An executable PE image file should not
be larger than 2GB on Windows. To support LBR collection for those large
applications, user can use llvm-objcopy to strip those debug sections
and produce a smaller binary for profiling. The original binary can then
be used as the debug binary to load pseudo probe and DWARF info.
---
Full diff: https://github.com/llvm/llvm-project/pull/175698.diff
3 Files Affected:
- (modified) llvm/test/tools/llvm-profgen/coff-profile.test (+5)
- (modified) llvm/tools/llvm-profgen/ProfiledBinary.cpp (+27-17)
- (modified) llvm/tools/llvm-profgen/ProfiledBinary.h (+4-4)
``````````diff
diff --git a/llvm/test/tools/llvm-profgen/coff-profile.test b/llvm/test/tools/llvm-profgen/coff-profile.test
index 6411642408f47..eb8ce02b86668 100644
--- a/llvm/test/tools/llvm-profgen/coff-profile.test
+++ b/llvm/test/tools/llvm-profgen/coff-profile.test
@@ -3,6 +3,11 @@
; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/coff-profile.perfscript --binary=%S/Inputs/coff-profile.exe --output=%t
; RUN: FileCheck %s --input-file %t --check-prefix=PROBE
+; RUN: mkdir %t.dir
+; RUN: llvm-objcopy --strip-debug --remove-section=.pseudo_probe --remove-section=.pseudo_probe_desc %S/Inputs/coff-profile.exe %t.dir/coff-profile.exe
+; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/coff-profile.perfscript --binary=%t.dir/coff-profile.exe --debug-binary=%S/Inputs/coff-profile.exe --output=%t
+; RUN: FileCheck %s --input-file %t --check-prefix=PROBE
+
DWARF: main:31341:0
DWARF-NEXT: 0: 0
DWARF-NEXT: 3: 0
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index aa16b66b25882..c71301fa80614 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -248,24 +248,33 @@ void ProfiledBinary::load() {
// Load debug info of subprograms from DWARF section.
// If path of debug info binary is specified, use the debug info from it,
// otherwise use the debug info from the executable binary.
+ OwningBinary<Binary> DebugBinary;
if (!DebugBinaryPath.empty()) {
- OwningBinary<Binary> DebugPath =
- unwrapOrError(createBinary(DebugBinaryPath), DebugBinaryPath);
- loadSymbolsFromDWARF(*cast<ObjectFile>(DebugPath.getBinary()));
+ DebugBinary = unwrapOrError(createBinary(DebugBinaryPath), DebugBinaryPath);
+ ObjectFile *DebugObj = cast<ObjectFile>(DebugBinary.getBinary());
+ loadSymbolsFromDWARF(*DebugObj);
+ checkPseudoProbe(DebugObj, DebugBinaryPath);
} else {
- loadSymbolsFromDWARF(*cast<ObjectFile>(&ExeBinary));
+ loadSymbolsFromDWARF(*Obj);
}
+ // Try to load pseudo probe from debug binary if it exists, otherwise try to
+ // load it from binary.
+ bool IsPseudoProbeInDebugBin = usePseudoProbes();
+ if (!IsPseudoProbeInDebugBin)
+ checkPseudoProbe(Obj, Path);
+
DisassembleFunctionSet.insert_range(DisassembleFunctions);
- checkPseudoProbe(Obj);
- if (UsePseudoProbes)
+ if (usePseudoProbes())
populateSymbolAddressList(Obj);
if (ShowDisassemblyOnly)
- decodePseudoProbe(Obj);
+ decodePseudoProbe(IsPseudoProbeInDebugBin
+ ? cast<ObjectFile>(DebugBinary.getBinary())
+ : Obj);
- if (LoadFunctionFromSymbol && UsePseudoProbes)
+ if (LoadFunctionFromSymbol && usePseudoProbes())
loadSymbolsFromSymtab(Obj);
// Disassemble the text sections.
@@ -426,7 +435,8 @@ void ProfiledBinary::setPreferredTextSegmentAddresses(const ObjectFile *Obj) {
llvm_unreachable("invalid object format");
}
-void ProfiledBinary::checkPseudoProbe(const ObjectFile *Obj) {
+void ProfiledBinary::checkPseudoProbe(const ObjectFile *Obj,
+ StringRef ObjPath) {
if (UseDwarfCorrelation)
return;
@@ -445,12 +455,12 @@ void ProfiledBinary::checkPseudoProbe(const ObjectFile *Obj) {
}
}
- // set UsePseudoProbes flag, used for PerfReader
- UsePseudoProbes = HasProbeDescSection && HasPseudoProbeSection;
+ if (HasProbeDescSection && HasPseudoProbeSection)
+ PseudoProbeBinPath = ObjPath;
}
void ProfiledBinary::decodePseudoProbe(const ObjectFile *Obj) {
- if (!UsePseudoProbes)
+ if (!usePseudoProbes())
return;
MCPseudoProbeDecoder::Uint64Set GuidFilter;
@@ -525,9 +535,9 @@ void ProfiledBinary::decodePseudoProbe(const ObjectFile *Obj) {
}
void ProfiledBinary::decodePseudoProbe() {
- OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path);
- Binary &ExeBinary = *OBinary.getBinary();
- auto *Obj = cast<ObjectFile>(&ExeBinary);
+ OwningBinary<Binary> OBinary =
+ unwrapOrError(createBinary(PseudoProbeBinPath), PseudoProbeBinPath);
+ auto *Obj = cast<ObjectFile>(OBinary.getBinary());
decodePseudoProbe(Obj);
}
@@ -1122,7 +1132,7 @@ void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t RangeBegin,
do {
const SampleContextFrameVector SymbolizedCallStack =
- getFrameLocationStack(IP.Address, UsePseudoProbes);
+ getFrameLocationStack(IP.Address, usePseudoProbes());
uint64_t Size = AddressToInstSizeMap[IP.Address];
// Record instruction size for the corresponding context
FuncSizeTracker.addInstructionForContext(SymbolizedCallStack, Size);
@@ -1150,7 +1160,7 @@ void ProfiledBinary::computeInlinedContextSizeForFunc(
}
void ProfiledBinary::loadSymbolsFromPseudoProbe() {
- if (!UsePseudoProbes)
+ if (!usePseudoProbes())
return;
const AddressProbesMap &Address2ProbesMap = getAddress2ProbesMap();
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index 1a83f8221df11..c3a60655356fc 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -203,6 +203,8 @@ class ProfiledBinary {
std::string Path;
// Path of the debug info binary.
std::string DebugBinaryPath;
+ // Path of the pseudo probe binary, either Path or DebugBinaryPath if present.
+ StringRef PseudoProbeBinPath;
// The target triple.
Triple TheTriple;
// Path of symbolizer path which should be pointed to binary with debug info.
@@ -319,8 +321,6 @@ class ProfiledBinary {
// Function name to probe frame map for top-level outlined functions.
StringMap<MCDecodedPseudoProbeInlineTree *> TopLevelProbeFrameMap;
- bool UsePseudoProbes = false;
-
bool UseFSDiscriminator = false;
// Whether we need to symbolize all instructions to get function context size.
@@ -355,7 +355,7 @@ class ProfiledBinary {
void setPreferredTextSegmentAddresses(const object::COFFObjectFile *Obj,
StringRef FileName);
- void checkPseudoProbe(const object::ObjectFile *Obj);
+ void checkPseudoProbe(const object::ObjectFile *Obj, StringRef ObjPath);
void decodePseudoProbe(const object::ObjectFile *Obj);
@@ -482,7 +482,7 @@ class ProfiledBinary {
size_t getCodeAddrVecSize() const { return CodeAddressVec.size(); }
- bool usePseudoProbes() const { return UsePseudoProbes; }
+ bool usePseudoProbes() const { return !PseudoProbeBinPath.empty(); }
bool useFSDiscriminator() const { return UseFSDiscriminator; }
bool isKernel() const { return IsKernel; }
``````````
</details>
https://github.com/llvm/llvm-project/pull/175698
More information about the llvm-commits
mailing list