test: Run bench sanity checks in parallel with functional tests
What changed, and why it matters
This commit reorganizes how Bitcoin Core runs its benchmark sanity checks. Previously, the bench_bitcoin -sanity-check command was run as a separate CI step and as a CMake test. Now, it is run as part of the functional test suite, with each individual benchmark sanity check executed in parallel alongside other functional tests. There is no change to production code, consensus logic, wallet handling, or network behavior. It is purely a testing infrastructure change.
No security action required. This is a benign CI/test refactoring. Reviewers may optionally verify that the new functional test correctly discovers all benchmarks and that the parallel execution does not introduce resource contention in CI.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit removes the standalone bench_sanity_check CMake test and the explicit ‘Run benchmarks’ step from the Windows CI workflow. It introduces a new functional test script, tool_bench_sanity_check.py, which invokes bench_bitcoin with -filter=
Changed components
test/functional/test_runner.pytest/functional/tool_bench_sanity_check.py.github/workflows/ci.ymlsrc/bench/CMakeLists.txtInspect captured patch +62 / −7
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8d94b1d6..c8deeb46 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -484,9 +484,6 @@ jobs:
./src/univalue/object.exe
./src/univalue/unitester.exe
- - name: Run benchmarks
- run: ./bin/bench_bitcoin.exe -sanity-check
-
- name: Adjust paths in test/config.ini
shell: pwsh
run: |
diff --git a/src/bench/CMakeLists.txt b/src/bench/CMakeLists.txt
index e0e03b1d..50b29a14 100644
--- a/src/bench/CMakeLists.txt
+++ b/src/bench/CMakeLists.txt
@@ -84,8 +84,4 @@ if(ENABLE_WALLET)
target_link_libraries(bench_bitcoin bitcoin_wallet)
endif()
-add_test(NAME bench_sanity_check
- COMMAND bench_bitcoin -sanity-check
-)
-
install_binary_component(bench_bitcoin INTERNAL)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index d63dbade..45882714 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -29,6 +29,11 @@ import sys
import tempfile
import re
import logging
+from test_framework.util import (
+ Binaries,
+ export_env_build_path,
+ get_binary_paths,
+)
# Minimum amount of space to run the tests.
MIN_FREE_SPACE = 1.1 * 1024 * 1024 * 1024
@@ -87,7 +92,12 @@ EXTENDED_SCRIPTS = [
'feature_index_prune.py',
]
+# Special script to run each bench sanity check
+TOOL_BENCH_SANITY_CHECK = "tool_bench_sanity_check.py"
+
BASE_SCRIPTS = [
+ # Special scripts that are "expanded" later
+ TOOL_BENCH_SANITY_CHECK,
# Scripts that are run by default.
# Longest test should go first, to favor running tests in parallel
# vv Tests less than 5m vv
@@ -457,6 +467,8 @@ def main():
print("Re-compile with the -DBUILD_DAEMON=ON build option")
sys.exit(1)
+ export_env_build_path(config)
+
# Build tests
test_list = deque()
if tests:
@@ -511,6 +523,15 @@ def main():
# Exclude all variants of a test
remove_tests([test for test in test_list if test.split('.py')[0] == exclude_test.split('.py')[0]])
+ if config["components"].getboolean("BUILD_BENCH") and TOOL_BENCH_SANITY_CHECK in test_list:
+ # Remove it, and expand it for each bench in the list
+ test_list.remove(TOOL_BENCH_SANITY_CHECK)
+ bench_cmd = Binaries(get_binary_paths(config), bin_dir=None).bench_argv() + ["-list"]
+ bench_list = subprocess.check_output(bench_cmd, text=True).splitlines()
+ bench_list = [f"{TOOL_BENCH_SANITY_CHECK} --bench={b}" for b in bench_list]
+ # Start with special scripts (variable, unknown runtime)
+ test_list.extendleft(reversed(bench_list))
+
if args.filter:
test_list = deque(filter(re.compile(args.filter).search, test_list))
diff --git a/test/functional/tool_bench_sanity_check.py b/test/functional/tool_bench_sanity_check.py
new file mode 100755
index 00000000..d2958786
--- /dev/null
+++ b/test/functional/tool_bench_sanity_check.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+# Copyright (c) The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or https://opensource.org/license/mit/.
+"""Special script to run each bench sanity check
+"""
+import shlex
+import subprocess
+
+from test_framework.test_framework import BitcoinTestFramework
+
+
+class BenchSanityCheck(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 0 # No node/datadir needed
+
+ def setup_network(self):
+ pass
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_bitcoin_bench()
+
+ def add_options(self, parser):
+ parser.add_argument(
+ "--bench",
+ default=".*",
+ help="Regex to filter the bench to run (default=%(default)s)",
+ )
+
+ def run_test(self):
+ cmd = self.get_binaries().bench_argv() + [
+ f"-filter={self.options.bench}",
+ "-sanity-check",
+ ]
+ self.log.info(f"Starting: {shlex.join(cmd)}")
+ subprocess.run(cmd, check=True)
+ self.log.info("Success!")
+
+
+if __name__ == "__main__":
+ BenchSanityCheck(__file__).main()
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.