[llvm] [BOLT] Add --instrument-funcs-file option to scope instrumentation (PR #197226)

YongKang Zhu via llvm-commits llvm-commits at lists.llvm.org
Tue May 12 08:47:40 PDT 2026


https://github.com/yozhu created https://github.com/llvm/llvm-project/pull/197226

Adds a new option that takes a file containing one function name per
line (exact match) and restricts instrumentation to those functions.
Composes with --instrument-hot-only as an AND filter.

>From 5a806f7ec9959f7f0dce38110b90f38cec463281 Mon Sep 17 00:00:00 2001
From: YongKang Zhu <yongzhu at fb.com>
Date: Mon, 11 May 2026 10:38:48 -0700
Subject: [PATCH] [BOLT] Add --instrument-funcs-file option to scope
 instrumentation

Adds a new option that takes a file containing one function name per
line (exact match) and restricts instrumentation to those functions.
Composes with --instrument-hot-only as an AND filter.
---
 bolt/lib/Passes/Instrumentation.cpp   | 41 +++++++++++++-
 bolt/test/X86/instrument-funcs-file.s | 82 +++++++++++++++++++++++++++
 2 files changed, 121 insertions(+), 2 deletions(-)
 create mode 100644 bolt/test/X86/instrument-funcs-file.s

diff --git a/bolt/lib/Passes/Instrumentation.cpp b/bolt/lib/Passes/Instrumentation.cpp
index ffcfb26415971..ae9faf4e9cc2d 100644
--- a/bolt/lib/Passes/Instrumentation.cpp
+++ b/bolt/lib/Passes/Instrumentation.cpp
@@ -15,8 +15,10 @@
 #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h"
 #include "bolt/Utils/CommandLineOpts.h"
 #include "bolt/Utils/Utils.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/RWMutex.h"
+#include <fstream>
 #include <queue>
 #include <stack>
 
@@ -76,6 +78,13 @@ cl::opt<bool> InstrumentationWaitForks(
              "(use with instrumentation-sleep-time option)"),
     cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
 
+cl::opt<std::string> InstrumentFuncsFile(
+    "instrument-funcs-file",
+    cl::desc("file with list of function names (one per line) to instrument; "
+             "only functions whose name exactly matches a line in this file "
+             "will be instrumented"),
+    cl::Optional, cl::cat(BoltInstrCategory));
+
 cl::opt<bool>
     InstrumentHotOnly("instrument-hot-only",
                       cl::desc("only insert instrumentation on hot functions "
@@ -643,9 +652,37 @@ Error Instrumentation::runOnFunctions(BinaryContext &BC) {
 
   createAuxiliaryFunctions(BC);
 
+  const bool HasInstrumentFuncsFilter = !opts::InstrumentFuncsFile.empty();
+  StringSet<> InstrumentFuncsSet;
+  if (HasInstrumentFuncsFilter) {
+    std::ifstream FuncsFile(opts::InstrumentFuncsFile, std::ios::in);
+    if (!FuncsFile)
+      return createFatalBOLTError(Twine("instrument-funcs-file \"") +
+                                  Twine(opts::InstrumentFuncsFile) +
+                                  Twine("\" can't be opened."));
+    std::string FuncName;
+    while (std::getline(FuncsFile, FuncName))
+      if (!FuncName.empty())
+        InstrumentFuncsSet.insert(FuncName);
+  }
+
   ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {
-    return (!BF.isSimple() || BF.isIgnored() ||
-            (opts::InstrumentHotOnly && !BF.getKnownExecutionCount()));
+    if (!BF.isSimple() || BF.isIgnored())
+      return true;
+    if (opts::InstrumentHotOnly && !BF.getKnownExecutionCount())
+      return true;
+    if (HasInstrumentFuncsFilter) {
+      bool Found = false;
+      for (const StringRef Name : BF.getNames()) {
+        if (InstrumentFuncsSet.contains(Name)) {
+          Found = true;
+          break;
+        }
+      }
+      if (!Found)
+        return true;
+    }
+    return false;
   };
 
   ParallelUtilities::WorkFuncWithAllocTy WorkFun =
diff --git a/bolt/test/X86/instrument-funcs-file.s b/bolt/test/X86/instrument-funcs-file.s
new file mode 100644
index 0000000000000..18aefd8cce0ed
--- /dev/null
+++ b/bolt/test/X86/instrument-funcs-file.s
@@ -0,0 +1,82 @@
+# Test --instrument-funcs-file, alone and combined with --instrument-hot-only.
+#
+# The binary defines three functions (foo, bar, baz). We attach a profile that
+# only marks foo as hot. With --instrument-funcs-file listing foo and bar, only
+# those two are instrumented. Adding --instrument-hot-only further restricts
+# instrumentation to foo (the only function that is both listed and hot).
+
+# REQUIRES: system-linux,bolt-runtime
+
+# RUN: %clang %cflags %s -o %t.exe -Wl,-q
+# RUN: link_fdata %s %t.exe %t.fdata
+
+# Funcs file lists foo and bar (baz is intentionally omitted).
+# RUN: echo "foo" > %t.funcs
+# RUN: echo "bar" >> %t.funcs
+
+# Test A: only --instrument-funcs-file. Both foo and bar get instrumented.
+# RUN: llvm-bolt --instrument --instrument-funcs-file=%t.funcs \
+# RUN:     -o %t.a.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-A
+
+# Test B: --instrument-funcs-file combined with --instrument-hot-only. Profile
+# marks only foo as hot, so bar is filtered out by --instrument-hot-only.
+# RUN: llvm-bolt --instrument --instrument-funcs-file=%t.funcs \
+# RUN:     --instrument-hot-only --data %t.fdata \
+# RUN:     -o %t.b.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-B
+
+# Test C: empty file means "no functions match", so nothing is instrumented.
+# RUN: rm -f %t.empty && touch %t.empty
+# RUN: llvm-bolt --instrument --instrument-funcs-file=%t.empty \
+# RUN:     -o %t.c.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-C
+
+# Test D: missing file produces a fatal error.
+# RUN: not llvm-bolt --instrument --instrument-funcs-file=%t.missing \
+# RUN:     -o %t.d.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-D
+
+# CHECK-A: BOLT-INSTRUMENTER: Number of function descriptors: 2
+# CHECK-B: BOLT-INSTRUMENTER: Number of function descriptors: 1
+# CHECK-C: BOLT-INSTRUMENTER: Number of function descriptors: 0
+# CHECK-D: instrument-funcs-file {{.*}}.missing{{.*}} can't be opened
+
+    .text
+    .globl _start
+    .type _start, %function
+_start:
+    call foo
+    call bar
+    call baz
+    retq
+    .size _start, .-_start
+
+    .globl foo
+    .type foo, %function
+foo:
+# FDATA: 0 [unknown] 0 1 foo 0 0 100
+    retq
+    .size foo, .-foo
+
+    .globl bar
+    .type bar, %function
+bar:
+    retq
+    .size bar, .-bar
+
+    .globl baz
+    .type baz, %function
+baz:
+    retq
+    .size baz, .-baz
+
+    .globl _init
+    .type _init, %function
+    # Force DT_INIT to be created (needed for instrumentation).
+_init:
+    retq
+    .size _init, .-_init
+
+    .globl _fini
+    .type _fini, %function
+    # Force DT_FINI to be created (needed for instrumentation).
+_fini:
+    retq
+    .size _fini, .-_fini



More information about the llvm-commits mailing list