Skip to content

Commit fda24db

Browse files
authored
[BOLT] Add dump-dot-func option for selective function CFG dumping (#153007)
## Change: * Added `--dump-dot-func` command-line option that allows users to dump CFGs only for specific functions instead of dumping all functions (the current only available option being `--dump-dot-all`) ## Usage: * Users can now specify function names or regex patterns (e.g., `--dump-dot-func=main,helper` or `--dump-dot-func="init.*`") to generate .dot files only for functions of interest * Aims to save time when analysing specific functions in large binaries (e.g., only dumping graphs for performance-critical functions identified through profiling) and we can now avoid reduce output clutter from generating thousands of unnecessary .dot files when analysing large binaries ## Testing The introduced test `dump-dot-func.test` confirms the new option does the following: - [x] 1. `dump-dot-func` can correctly filter a specified functions - [x] 2. Can achieve the above with regexes - [x] 3. Can do 1. with a list of functions - [x] No option specified creates no dot files - [x] Passing in a non-existent function generates no dumping messages - [x] `dump-dot-all` continues to work as expected
1 parent 7594b4b commit fda24db

File tree

6 files changed

+123
-2
lines changed

6 files changed

+123
-2
lines changed

bolt/docs/CommandLineArgumentReference.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@
138138
Dump function CFGs to graphviz format after each stage;enable '-print-loops'
139139
for color-coded blocks
140140

141+
- `--dump-dot-func=<func1,func2,func3...>`
142+
143+
Dump function CFGs to graphviz format for specified functions only;
144+
takes function name patterns (regex supported). Note: C++ function names
145+
must be passed using their mangled names
146+
141147
- `--dump-linux-exceptions`
142148

143149
Dump Linux kernel exception table

bolt/include/bolt/Utils/CommandLineOpts.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515

1616
#include "llvm/Support/CommandLine.h"
1717

18+
namespace llvm {
19+
namespace bolt {
20+
class BinaryFunction;
21+
}
22+
} // namespace llvm
23+
1824
namespace opts {
1925

2026
enum HeatmapModeKind {
@@ -100,6 +106,9 @@ extern llvm::cl::opt<unsigned> Verbosity;
100106
/// Return true if we should process all functions in the binary.
101107
bool processAllFunctions();
102108

109+
/// Return true if we should dump dot graphs for the given function.
110+
bool shouldDumpDot(const llvm::bolt::BinaryFunction &Function);
111+
103112
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
104113

105114
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;

bolt/lib/Rewrite/BinaryPassManager.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ namespace opts {
5252
extern cl::opt<bool> PrintAll;
5353
extern cl::opt<bool> PrintDynoStats;
5454
extern cl::opt<bool> DumpDotAll;
55+
extern bool shouldDumpDot(const bolt::BinaryFunction &Function);
5556
extern cl::opt<std::string> AsmDump;
5657
extern cl::opt<bolt::PLTCall::OptType> PLT;
5758
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
@@ -340,7 +341,7 @@ Error BinaryFunctionPassManager::runPasses() {
340341

341342
Function.print(BC.outs(), Message);
342343

343-
if (opts::DumpDotAll)
344+
if (opts::shouldDumpDot(Function))
344345
Function.dumpGraphForPass(PassIdName);
345346
}
346347
}

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,35 @@ cl::opt<bool> DumpDotAll(
115115
"enable '-print-loops' for color-coded blocks"),
116116
cl::Hidden, cl::cat(BoltCategory));
117117

118+
cl::list<std::string> DumpDotFunc(
119+
"dump-dot-func", cl::CommaSeparated,
120+
cl::desc(
121+
"dump function CFGs to graphviz format for specified functions only;"
122+
"takes function name patterns (regex supported)"),
123+
cl::value_desc("func1,func2,func3,..."), cl::Hidden, cl::cat(BoltCategory));
124+
125+
bool shouldDumpDot(const bolt::BinaryFunction &Function) {
126+
// If dump-dot-all is enabled, dump all functions
127+
if (DumpDotAll)
128+
return !Function.isIgnored();
129+
130+
// If no specific functions specified in dump-dot-func, don't dump any
131+
if (DumpDotFunc.empty())
132+
return false;
133+
134+
if (Function.isIgnored())
135+
return false;
136+
137+
// Check if function matches any of the specified patterns
138+
for (const std::string &Name : DumpDotFunc) {
139+
if (Function.hasNameRegex(Name)) {
140+
return true;
141+
}
142+
}
143+
144+
return false;
145+
}
146+
118147
static cl::list<std::string>
119148
ForceFunctionNames("funcs",
120149
cl::CommaSeparated,
@@ -3569,7 +3598,7 @@ void RewriteInstance::postProcessFunctions() {
35693598
if (opts::PrintAll || opts::PrintCFG)
35703599
Function.print(BC->outs(), "after building cfg");
35713600

3572-
if (opts::DumpDotAll)
3601+
if (opts::shouldDumpDot(Function))
35733602
Function.dumpGraphForPass("00_build-cfg");
35743603

35753604
if (opts::PrintLoopInfo) {

bolt/test/Inputs/multi-func.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <iostream>
2+
3+
// Multiple functions to test selective dumping
4+
int add(int a, int b) { return a + b; }
5+
6+
int multiply(int a, int b) { return a * b; }
7+
8+
int main_helper() {
9+
std::cout << "Helper function" << std::endl;
10+
return 42;
11+
}
12+
13+
int main_secondary() { return add(5, 3); }
14+
15+
void other_function() { std::cout << "Other function" << std::endl; }
16+
17+
int main() {
18+
int result = add(10, 20);
19+
result = multiply(result, 2);
20+
main_helper();
21+
main_secondary();
22+
other_function();
23+
return result;
24+
}

bolt/test/dump-dot-func.test

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Test the --dump-dot-func option with multiple functions
2+
# (includes tests for both mangled/unmangled names)
3+
4+
RUN: %clang++ %p/Inputs/multi-func.cpp -o %t.exe -Wl,-q
5+
6+
# Test 1: --dump-dot-func with specific function name (mangled)
7+
RUN: llvm-bolt %t.exe -o %t.bolt1 --dump-dot-func=_Z3addii -v=1 2>&1 | FileCheck %s --check-prefix=ADD
8+
9+
# Test 2: --dump-dot-func with regex pattern (main.*)
10+
RUN: llvm-bolt %t.exe -o %t.bolt2 --dump-dot-func="main.*" -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-REGEX
11+
12+
# Test 3: --dump-dot-func with multiple specific functions (mangled names)
13+
RUN: llvm-bolt %t.exe -o %t.bolt3 --dump-dot-func=_Z3addii,_Z8multiplyii -v=1 2>&1 | FileCheck %s --check-prefix=MULTI
14+
15+
# Test 4: No option specified should create no dot files
16+
RUN: llvm-bolt %t.exe -o %t.bolt4 2>&1 | FileCheck %s --check-prefix=NONE
17+
18+
# Test 5: --dump-dot-func with non-existent function
19+
RUN: llvm-bolt %t.exe -o %t.bolt5 --dump-dot-func=nonexistent -v=1 2>&1 | FileCheck %s --check-prefix=NONEXISTENT
20+
21+
# Test 6: Backward compatibility - --dump-dot-all should still work
22+
RUN: llvm-bolt %t.exe -o %t.bolt6 --dump-dot-all -v=1 2>&1 | FileCheck %s --check-prefix=ALL
23+
24+
# Test 7: Test with unmangled function name (main function)
25+
RUN: llvm-bolt %t.exe -o %t.bolt7 --dump-dot-func=main -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-UNMANGLED
26+
27+
# Check that specific functions are dumped
28+
ADD: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
29+
ADD-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
30+
ADD-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
31+
ADD-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
32+
33+
MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
34+
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
35+
MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
36+
37+
MULTI-DAG: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
38+
MULTI-DAG: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot
39+
MULTI-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
40+
MULTI-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot
41+
42+
# Should be no dumping messages when no option is specified
43+
NONE-NOT: BOLT-INFO: dumping CFG
44+
45+
# Should be no dumping messages for non-existent function
46+
NONEXISTENT-NOT: BOLT-INFO: dumping CFG
47+
48+
ALL: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
49+
50+
MAIN-UNMANGLED: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
51+
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot
52+
MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot

0 commit comments

Comments
 (0)