From 7280499e8ed6f0a67268fa0e97ca3a7a72e1cb0c Mon Sep 17 00:00:00 2001 From: Tom Cobley <43605582+tomcobley@users.noreply.github.com> Date: Tue, 28 Jun 2022 10:16:28 +0100 Subject: [PATCH 001/561] Remove redundant formatting tags (#1420) --- docs/user_guide.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index f96b7dfd03..1e26f5c032 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -383,17 +383,14 @@ short-hand. The following macro will pick a few appropriate arguments in the product of the two specified ranges and will generate a benchmark for each such pair. -{% raw %} ```c++ BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}}); ``` -{% endraw %} Some benchmarks may require specific argument values that cannot be expressed with `Ranges`. In this case, `ArgsProduct` offers the ability to generate a benchmark input for each combination in the product of the supplied vectors. -{% raw %} ```c++ BENCHMARK(BM_SetInsert) ->ArgsProduct({{1<<10, 3<<10, 8<<10}, {20, 40, 60, 80}}) @@ -412,7 +409,6 @@ BENCHMARK(BM_SetInsert) ->Args({3<<10, 80}) ->Args({8<<10, 80}); ``` -{% endraw %} For the most common scenarios, helper methods for creating a list of integers for a given sparse or dense range are provided. @@ -698,7 +694,6 @@ is 1k a 1000 (default, `benchmark::Counter::OneK::kIs1000`), or 1024 When you're compiling in C++11 mode or later you can use `insert()` with `std::initializer_list`: -{% raw %} ```c++ // With C++11, this can be done: state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}}); @@ -707,7 +702,6 @@ When you're compiling in C++11 mode or later you can use `insert()` with state.counters["Bar"] = numBars; state.counters["Baz"] = numBazs; ``` -{% endraw %} ### Counter Reporting @@ -876,7 +870,6 @@ is measured. But sometimes, it is necessary to do some work inside of that loop, every iteration, but without counting that time to the benchmark time. That is possible, although it is not recommended, since it has high overhead. -{% raw %} ```c++ static void BM_SetInsert_With_Timer_Control(benchmark::State& state) { std::set data; @@ -891,7 +884,6 @@ static void BM_SetInsert_With_Timer_Control(benchmark::State& state) { } BENCHMARK(BM_SetInsert_With_Timer_Control)->Ranges({{1<<10, 8<<10}, {128, 512}}); ``` -{% endraw %} From dfdda57a128cfb6ad391141c4a8e480cd8e4568a Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Mon, 4 Jul 2022 11:27:05 +0200 Subject: [PATCH 002/561] Fix DoNotOptimize() GCC compile error with some types (#1340) (#1424) Non-const DoNotOptimize() can't compile when used with some types. Example of code which can't compile: char buffer3[3] = ""; benchmark::DoNotOptimize(buffer3); Error message: error: impossible constraint in 'asm' asm volatile("" : "+r"(value) : : "memory"); Introduced in 8545dfb (Fix DoNotOptimize() GCC copy overhead (#1340) (#1410)) The cause is compiler can't work with the +r constraint for types that can't be placed perfectly in registers. For example, char array[3] can't be perfectly fit in register on x86_64 so it requires placed in memory but constraint doesn't allow that. Solution - Use +m,r constraint for the small objects so the compiler can decide to use register or/and memory - For the big objects +m constraint is used which allows avoiding extra copy bug(see #1340) - The same approach is used for the const version of DoNotOptimize() although the const version works fine with the "r" constraint only. Using mixed r,m constraint looks more general solution. See - Issue #1340 ([BUG] DoNotOptimize() adds overhead with extra copy of argument(gcc)) - Pull request #1410 (Fix DoNotOptimize() GCC copy overhead (#1340) #1410) - Commit 8545dfb (Fix DoNotOptimize() GCC copy overhead (#1340) (#1410)) --- include/benchmark/benchmark.h | 4 ++-- test/donotoptimize_test.cc | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index a4fc52df6f..58a8a30226 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -468,7 +468,7 @@ inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value && (sizeof(Tp) <= sizeof(Tp*))>::type DoNotOptimize(Tp const& value) { - asm volatile("" : : "r"(value) : "memory"); + asm volatile("" : : "r,m"(value) : "memory"); } template @@ -484,7 +484,7 @@ inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value && (sizeof(Tp) <= sizeof(Tp*))>::type DoNotOptimize(Tp& value) { - asm volatile("" : "+r"(value) : : "memory"); + asm volatile("" : "+m,r"(value) : : "memory"); } template diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc index 5c0d3b6eac..96881666c9 100644 --- a/test/donotoptimize_test.cc +++ b/test/donotoptimize_test.cc @@ -29,6 +29,15 @@ struct BitRef { int main(int, char*[]) { // this test verifies compilation of DoNotOptimize() for some types + char buffer1[1] = ""; + benchmark::DoNotOptimize(buffer1); + + char buffer2[2] = ""; + benchmark::DoNotOptimize(buffer2); + + char buffer3[3] = ""; + benchmark::DoNotOptimize(buffer3); + char buffer8[8] = ""; benchmark::DoNotOptimize(buffer8); @@ -39,6 +48,25 @@ int main(int, char*[]) { benchmark::DoNotOptimize(buffer1024); benchmark::DoNotOptimize(&buffer1024[0]); + const char const_buffer1[1] = ""; + benchmark::DoNotOptimize(const_buffer1); + + const char const_buffer2[2] = ""; + benchmark::DoNotOptimize(const_buffer2); + + const char const_buffer3[3] = ""; + benchmark::DoNotOptimize(const_buffer3); + + const char const_buffer8[8] = ""; + benchmark::DoNotOptimize(const_buffer8); + + const char const_buffer20[20] = ""; + benchmark::DoNotOptimize(const_buffer20); + + const char const_buffer1024[1024] = ""; + benchmark::DoNotOptimize(const_buffer1024); + benchmark::DoNotOptimize(&const_buffer1024[0]); + int x = 123; benchmark::DoNotOptimize(x); benchmark::DoNotOptimize(&x); From 4136c4a3c57a3d1d5385da6d08fa4438fc352b75 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Mon, 4 Jul 2022 16:29:03 +0700 Subject: [PATCH 003/561] Expose default help printer function (#1425) * Pass the default help string into custom help printer Improves #1329. * Expose default help printer --- include/benchmark/benchmark.h | 4 +++- src/benchmark.cc | 44 +++++++++++++++++------------------ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 58a8a30226..b25b001050 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -291,8 +291,10 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); namespace benchmark { class BenchmarkReporter; +BENCHMARK_EXPORT void PrintDefaultHelp(); + BENCHMARK_EXPORT void Initialize(int* argc, char** argv, - void (*HelperPrinterf)() = NULL); + void (*HelperPrinterf)() = PrintDefaultHelp); BENCHMARK_EXPORT void Shutdown(); // Report to stdout all arguments in 'argv' as unrecognized except the first. diff --git a/src/benchmark.cc b/src/benchmark.cc index 254b95ef9e..88167f6958 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -567,28 +567,7 @@ namespace internal { void (*HelperPrintf)(); void PrintUsageAndExit() { - if (HelperPrintf) { - HelperPrintf(); - } else { - fprintf(stdout, - "benchmark" - " [--benchmark_list_tests={true|false}]\n" - " [--benchmark_filter=]\n" - " [--benchmark_min_time=]\n" - " [--benchmark_min_warmup_time=]\n" - " [--benchmark_repetitions=]\n" - " [--benchmark_enable_random_interleaving={true|false}]\n" - " [--benchmark_report_aggregates_only={true|false}]\n" - " [--benchmark_display_aggregates_only={true|false}]\n" - " [--benchmark_format=]\n" - " [--benchmark_out=]\n" - " [--benchmark_out_format=]\n" - " [--benchmark_color={auto|true|false}]\n" - " [--benchmark_counters_tabular={true|false}]\n" - " [--benchmark_context==,...]\n" - " [--benchmark_time_unit={ns|us|ms|s}]\n" - " [--v=]\n"); - } + HelperPrintf(); exit(0); } @@ -670,6 +649,27 @@ int InitializeStreams() { } // end namespace internal +void PrintDefaultHelp() { + fprintf(stdout, + "benchmark" + " [--benchmark_list_tests={true|false}]\n" + " [--benchmark_filter=]\n" + " [--benchmark_min_time=]\n" + " [--benchmark_min_warmup_time=]\n" + " [--benchmark_repetitions=]\n" + " [--benchmark_enable_random_interleaving={true|false}]\n" + " [--benchmark_report_aggregates_only={true|false}]\n" + " [--benchmark_display_aggregates_only={true|false}]\n" + " [--benchmark_format=]\n" + " [--benchmark_out=]\n" + " [--benchmark_out_format=]\n" + " [--benchmark_color={auto|true|false}]\n" + " [--benchmark_counters_tabular={true|false}]\n" + " [--benchmark_context==,...]\n" + " [--benchmark_time_unit={ns|us|ms|s}]\n" + " [--v=]\n"); +} + void Initialize(int* argc, char** argv, void (*HelperPrintf)()) { internal::ParseCommandLineFlags(argc, argv); internal::LogLevel() = FLAGS_v; From a8bc318b9b2ed4d9acc3fb876d117c8fd7e8d2e1 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 4 Jul 2022 12:15:49 +0100 Subject: [PATCH 004/561] fix cmake warning for libcxx setup --- .github/.libcxx-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/.libcxx-setup.sh b/.github/.libcxx-setup.sh index 56008403ae..957c86b157 100755 --- a/.github/.libcxx-setup.sh +++ b/.github/.libcxx-setup.sh @@ -17,7 +17,7 @@ cmake -DCMAKE_C_COMPILER=${C_COMPILER} \ -DLIBCXX_ABI_UNSTABLE=OFF \ -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ - -DLLVM_ENABLE_PROJECTS='libcxx;libcxxabi' \ + -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \ -S llvm -B llvm-build -G "Unix Makefiles" make -C llvm-build -j3 cxx cxxabi sudo make -C llvm-build install-cxx install-cxxabi From 0a95a422b984e9703fd2fe071abea3adbd666846 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 4 Jul 2022 12:35:55 +0100 Subject: [PATCH 005/561] fix dependabot numpy version warning --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 81ebfbfb6c..18def0ee3e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -numpy == 1.21 +numpy == 1.22 scipy == 1.5.4 pandas == 1.1.5 From 8205547ceb159527065bf760a87a2918c34b8006 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 5 Jul 2022 10:41:38 +0100 Subject: [PATCH 006/561] fix sanitizer builds by using clang 13 (#1426) * attempt to fix sanitizer builds by moving away from llvm head * extra verbosity * try clang 13 and add extra logging * get latest clang and try again --- .github/.libcxx-setup.sh | 4 ++-- .github/workflows/sanitizer.yml | 17 +++++++++++++++-- cmake/CXXFeatureCheck.cmake | 8 +++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/.libcxx-setup.sh b/.github/.libcxx-setup.sh index 957c86b157..c173111f63 100755 --- a/.github/.libcxx-setup.sh +++ b/.github/.libcxx-setup.sh @@ -10,8 +10,8 @@ fi # Build and install libc++ (Use unstable ABI for better sanitizer coverage) cd ./llvm-project -cmake -DCMAKE_C_COMPILER=${C_COMPILER} \ - -DCMAKE_CXX_COMPILER=${COMPILER} \ +cmake -DCMAKE_C_COMPILER=${CC} \ + -DCMAKE_CXX_COMPILER=${CXX} \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=/usr \ -DLIBCXX_ABI_UNSTABLE=OFF \ diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index bbfc782200..4f5b732057 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -45,11 +45,22 @@ jobs: echo "EXTRA_FLAGS=-g -O2 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all" >> $GITHUB_ENV echo "LIBCXX_SANITIZER=Thread" >> $GITHUB_ENV + - name: setup clang + if: matrix.compiler == 'clang' + uses: egor-tensin/setup-clang@v1 + with: + version: latest + platform: x64 + #run: | + #sudo apt update && sudo apt -y install clang-13 clang++-13 + #echo "CC=clang-13" >> $GITHUB_ENV + #echo "CXX=clang++-13" >> $GITHUB_ENV + - name: configure clang if: matrix.compiler == 'clang' run: | - echo "CC=clang" >> $GITHUB_ENV - echo "CXX=clang++" >> $GITHUB_ENV + echo "CC=cc" >> $GITHUB_ENV + echo "CXX=c++" >> $GITHUB_ENV - name: configure gcc if: matrix.compiler == 'gcc' @@ -61,6 +72,7 @@ jobs: - name: install llvm stuff if: matrix.compiler == 'clang' run: | + # sudo apt update && sudo apt -y install libc++-dev libc++abi-dev libc++1 libc++abi1 "${GITHUB_WORKSPACE}/.github/.libcxx-setup.sh" echo "EXTRA_CXX_FLAGS=\"-stdlib=libc++\"" >> $GITHUB_ENV @@ -71,6 +83,7 @@ jobs: shell: bash working-directory: ${{ runner.workspace }}/_build run: > + VERBOSE=1 cmake $GITHUB_WORKSPACE -DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF -DBENCHMARK_ENABLE_LIBPFM=OFF diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index 62e6741fe3..aa67f58e6d 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -38,7 +38,8 @@ function(cxx_feature_check FILE) try_compile(COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS} - LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES}) + LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} + OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) if(COMPILE_${FEATURE}) message(WARNING "If you see build failures due to cross compilation, try setting HAVE_${VAR} to 0") @@ -51,7 +52,8 @@ function(cxx_feature_check FILE) try_run(RUN_${FEATURE} COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS} - LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES}) + LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} + COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) endif() endif() @@ -61,7 +63,7 @@ function(cxx_feature_check FILE) add_definitions(-DHAVE_${VAR}) else() if(NOT COMPILE_${FEATURE}) - message(STATUS "Performing Test ${FEATURE} -- failed to compile") + message(STATUS "Performing Test ${FEATURE} -- failed to compile: ${COMPILE_OUTPUT_VAR}") else() message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run") endif() From ac8a6d3de91d7deca24d1505ec3b551d0d56bad4 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 5 Jul 2022 10:42:36 +0100 Subject: [PATCH 007/561] cleanup comments --- .github/workflows/sanitizer.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 4f5b732057..7fff2cea9c 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -51,10 +51,6 @@ jobs: with: version: latest platform: x64 - #run: | - #sudo apt update && sudo apt -y install clang-13 clang++-13 - #echo "CC=clang-13" >> $GITHUB_ENV - #echo "CXX=clang++-13" >> $GITHUB_ENV - name: configure clang if: matrix.compiler == 'clang' @@ -72,7 +68,6 @@ jobs: - name: install llvm stuff if: matrix.compiler == 'clang' run: | - # sudo apt update && sudo apt -y install libc++-dev libc++abi-dev libc++1 libc++abi1 "${GITHUB_WORKSPACE}/.github/.libcxx-setup.sh" echo "EXTRA_CXX_FLAGS=\"-stdlib=libc++\"" >> $GITHUB_ENV From 1531ee0d634d8563da6a3f36ea2597c95d1c2d46 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 7 Jul 2022 14:59:15 +0100 Subject: [PATCH 008/561] Correct typo in Passing Arguments section fixes #1419 --- docs/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 1e26f5c032..dde1f0e931 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -314,7 +314,7 @@ static void BM_memcpy(benchmark::State& state) { delete[] src; delete[] dst; } -BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); +BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(4<<10)->Arg(8<<10); ``` The preceding code is quite repetitive, and can be replaced with the following From 4efcc4746149ad0cfc59b06731ead74805c9c4b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cezary=20Skrzy=C5=84ski?= Date: Fri, 15 Jul 2022 13:18:45 +0200 Subject: [PATCH 009/561] Suppress nvcc `offsetof` warning (#1429) * Suppress nvcc offsetof warning * Update AUTHORS and CONTRIBUTORS --- AUTHORS | 1 + CONTRIBUTORS | 1 + src/benchmark.cc | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/AUTHORS b/AUTHORS index 5a39872fe0..7d689350b5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Alex Steele Andriy Berestovskyy Arne Beer Carto +Cezary Skrzyński Christian Wassermann Christopher Seymour Colin Braley diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 35a4cc66f0..4208e0cf51 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -29,6 +29,7 @@ Andriy Berestovskyy Arne Beer Bátor Tallér Billy Robert O'Neal III +Cezary Skrzyński Chris Kennelly Christian Wassermann Christopher Seymour diff --git a/src/benchmark.cc b/src/benchmark.cc index 88167f6958..6035491413 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -177,6 +177,10 @@ State::State(IterationCount max_iters, const std::vector& ranges, #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +#if defined(__CUDACC__) +#pragma nv_diagnostic push +#pragma nv_diag_suppress 1427 #endif // Offset tests to ensure commonly accessed data is on the first cache line. const int cache_line_size = 64; @@ -188,6 +192,9 @@ State::State(IterationCount max_iters, const std::vector& ranges, #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif +#if defined(__CUDACC__) +#pragma nv_diagnostic pop +#endif } void State::PauseTiming() { From 48c2d1c1ee54aaf583a3bec69f2a7e35f19b53da Mon Sep 17 00:00:00 2001 From: Ross McIlroy Date: Fri, 15 Jul 2022 18:06:53 +0100 Subject: [PATCH 010/561] Expose google_benchmark.State for python bindings. (#1430) Allows for type annotations. --- bindings/python/google_benchmark/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index ec651c14fb..23fbcf68cb 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -44,6 +44,7 @@ def my_benchmark(state): oNLogN, oAuto, oLambda, + State, ) @@ -64,6 +65,7 @@ def my_benchmark(state): "oNLogN", "oAuto", "oLambda", + "State", ] __version__ = "1.6.1" From 7a2024e961b8741ce46e83f226378b90e457ead3 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 18 Jul 2022 15:34:24 +0100 Subject: [PATCH 011/561] v1.6.2 bump --- CMakeLists.txt | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6880c1f362..f8c86c3f5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ foreach(p endif() endforeach() -project (benchmark VERSION 1.6.1 LANGUAGES CXX) +project (benchmark VERSION 1.6.2 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 23fbcf68cb..4d57c71732 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -68,7 +68,7 @@ def my_benchmark(state): "State", ] -__version__ = "1.6.1" +__version__ = "1.6.2" class __OptionMaker: From d4bc509bcd54266e80bef26d5829ea43ead2908e Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 18 Jul 2022 18:19:05 +0100 Subject: [PATCH 012/561] Fix SOVERSION of shared library Fixes #1434 --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70813129b2..8f471ea561 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,7 +22,7 @@ add_library(benchmark::benchmark ALIAS benchmark) set_target_properties(benchmark PROPERTIES OUTPUT_NAME "benchmark" VERSION ${GENERIC_LIB_VERSION} - SOVERSION 2 + SOVERSION ${GENERIC_LIB_SOVERSION} ) target_include_directories(benchmark PUBLIC $ From d845b7b3a27d54ad96280a29d61fa8988d4fddcf Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 19 Jul 2022 09:14:35 +0100 Subject: [PATCH 013/561] Also fix the SOVERSION for benchmark_main --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f471ea561..05ea023853 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,7 +64,7 @@ add_library(benchmark::benchmark_main ALIAS benchmark_main) set_target_properties(benchmark_main PROPERTIES OUTPUT_NAME "benchmark_main" VERSION ${GENERIC_LIB_VERSION} - SOVERSION 2 + SOVERSION ${GENERIC_LIB_SOVERSION} DEFINE_SYMBOL benchmark_EXPORTS ) target_link_libraries(benchmark_main PUBLIC benchmark::benchmark) From 7b3ac075177212dd75476253d72db992513e8024 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 20 Jul 2022 20:34:39 +0100 Subject: [PATCH 014/561] Stop generating the export header and just check it in (#1435) * Stop generating the export header and just check it in * format the new header * support windows * format the header again * avoid depending on internal macro * ensure we define the right thing for windows static builds * support older cmake * and for tests --- BUILD.bazel | 9 -- CMakeLists.txt | 1 - LICENSE | 32 ------ config/generate_export_header.bzl | 168 ------------------------------ include/benchmark/export.h | 47 +++++++++ src/CMakeLists.txt | 7 +- test/CMakeLists.txt | 4 + 7 files changed, 55 insertions(+), 213 deletions(-) delete mode 100644 config/generate_export_header.bzl create mode 100644 include/benchmark/export.h diff --git a/BUILD.bazel b/BUILD.bazel index 872adb0ff6..1621504720 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,14 +1,5 @@ licenses(["notice"]) -load("//:config/generate_export_header.bzl", "generate_export_header") - -# Generate header to provide ABI export symbols -generate_export_header( - out = "include/benchmark/export.h", - lib = "benchmark", - static_define = "BENCHMARK_STATIC_DEFINE", -) - config_setting( name = "qnx", constraint_values = ["@platforms//os:qnx"], diff --git a/CMakeLists.txt b/CMakeLists.txt index f8c86c3f5a..a44613e960 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,7 +130,6 @@ include(AddCXXCompilerFlag) include(CheckCXXCompilerFlag) include(CheckLibraryExists) include(CXXFeatureCheck) -include(GenerateExportHeader) check_library_exists(rt shm_open "" HAVE_LIB_RT) diff --git a/LICENSE b/LICENSE index a5c40b3ee1..d645695673 100644 --- a/LICENSE +++ b/LICENSE @@ -200,35 +200,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - - -Only benchmark/config/generate_export_header.bzl depends on the following licence: - - BSD 3-Clause License - -Copyright (c) [year], [fullname] - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/config/generate_export_header.bzl b/config/generate_export_header.bzl deleted file mode 100644 index bf98092d59..0000000000 --- a/config/generate_export_header.bzl +++ /dev/null @@ -1,168 +0,0 @@ -# -# Original file is located at: -# https://github.com/RobotLocomotion/drake/blob/bad032aeb09b13c7f8c87ed64b624c8d1e9adb30/tools/workspace/generate_export_header.bzl -# -# All components of Drake are licensed under the BSD 3-Clause License -# shown below. Where noted in the source code, some portions may -# be subject to other permissive, non-viral licenses. -# -# Copyright 2012-2016 Robot Locomotion Group @ CSAIL -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. Redistributions -# in binary form must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. Neither the name of -# the Massachusetts Institute of Technology nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# -*- python -*- - -# Defines the implementation actions to generate_export_header. -def _generate_export_header_impl(ctx): - windows_constraint = ctx.attr._windows_constraint[platform_common.ConstraintValueInfo] - output = ctx.outputs.out - - if ctx.target_platform_has_constraint(windows_constraint): - export_attr = "__declspec(dllexport)" - import_attr = "__declspec(dllimport)" - no_export_attr = "" - deprecated_attr = "__declspec(deprecated)" - else: - export_attr = "__attribute__((visibility(\"default\")))" - import_attr = "__attribute__((visibility(\"default\")))" - no_export_attr = "__attribute__((visibility(\"hidden\")))" - deprecated_attr = "__attribute__((__deprecated__))" - - content = [ - "#ifndef %s_H" % ctx.attr.export_macro_name, - "#define %s_H" % ctx.attr.export_macro_name, - "", - "#ifdef %s" % ctx.attr.static_define, - "# define %s" % ctx.attr.export_macro_name, - "# define %s" % ctx.attr.no_export_macro_name, - "#else", - "# ifndef %s" % ctx.attr.export_macro_name, - "# ifdef %s" % ctx.attr.export_import_condition, - "# define %s %s" % (ctx.attr.export_macro_name, export_attr), - "# else", - "# define %s %s" % (ctx.attr.export_macro_name, import_attr), - "# endif", - "# endif", - "# ifndef %s" % ctx.attr.no_export_macro_name, - "# define %s %s" % (ctx.attr.no_export_macro_name, no_export_attr), - "# endif", - "#endif", - "", - "#ifndef %s" % ctx.attr.deprecated_macro_name, - "# define %s %s" % (ctx.attr.deprecated_macro_name, deprecated_attr), - "#endif", - "", - "#ifndef %s" % ctx.attr.export_deprecated_macro_name, - "# define %s %s %s" % (ctx.attr.export_deprecated_macro_name, ctx.attr.export_macro_name, ctx.attr.deprecated_macro_name), # noqa - "#endif", - "", - "#ifndef %s" % ctx.attr.no_export_deprecated_macro_name, - "# define %s %s %s" % (ctx.attr.no_export_deprecated_macro_name, ctx.attr.no_export_macro_name, ctx.attr.deprecated_macro_name), # noqa - "#endif", - "", - "#endif", - ] - - ctx.actions.write(output = output, content = "\n".join(content) + "\n") - -# Defines the rule to generate_export_header. -_generate_export_header_gen = rule( - attrs = { - "out": attr.output(mandatory = True), - "export_import_condition": attr.string(), - "export_macro_name": attr.string(), - "deprecated_macro_name": attr.string(), - "export_deprecated_macro_name": attr.string(), - "no_export_macro_name": attr.string(), - "no_export_deprecated_macro_name": attr.string(), - "static_define": attr.string(), - "_windows_constraint": attr.label(default = "@platforms//os:windows"), - }, - output_to_genfiles = True, - implementation = _generate_export_header_impl, -) - -def generate_export_header( - lib = None, - name = None, - out = None, - export_import_condition = None, - export_macro_name = None, - deprecated_macro_name = None, - export_deprecated_macro_name = None, - no_export_macro_name = None, - no_export_deprecated_macro_name = None, - static_define = None, - **kwargs): - """ - Creates a rule to generate an export header for a named library. - - This is an incomplete implementation of CMake's generate_export_header. (In - particular, it assumes a platform that uses - __attribute__((visibility("default"))) to decorate exports.) - - By default, the rule will have a mangled name related to the library name, - and will produce "_export.h". - - The CMake documentation of the generate_export_header macro is: - https://cmake.org/cmake/help/latest/module/GenerateExportHeader.html - - """ - - if name == None: - name = "__%s_export_h" % lib - if out == None: - out = "%s_export.h" % lib - if export_import_condition == None: - # CMake does not uppercase the _EXPORTS define. - export_import_condition = "%s_EXPORTS" % lib - if export_macro_name == None: - export_macro_name = "%s_EXPORT" % lib.upper() - if deprecated_macro_name == None: - deprecated_macro_name = "%s_DEPRECATED" % lib.upper() - if export_deprecated_macro_name == None: - export_deprecated_macro_name = "%s_DEPRECATED_EXPORT" % lib.upper() - if no_export_macro_name == None: - no_export_macro_name = "%s_NO_EXPORT" % lib.upper() - if no_export_deprecated_macro_name == None: - no_export_deprecated_macro_name = \ - "%s_DEPRECATED_NO_EXPORT" % lib.upper() - if static_define == None: - static_define = "%s_STATIC_DEFINE" % lib.upper() - - _generate_export_header_gen( - name = name, - out = out, - export_import_condition = export_import_condition, - export_macro_name = export_macro_name, - deprecated_macro_name = deprecated_macro_name, - export_deprecated_macro_name = export_deprecated_macro_name, - no_export_macro_name = no_export_macro_name, - no_export_deprecated_macro_name = no_export_deprecated_macro_name, - static_define = static_define, - **kwargs - ) diff --git a/include/benchmark/export.h b/include/benchmark/export.h new file mode 100644 index 0000000000..f96f8596cd --- /dev/null +++ b/include/benchmark/export.h @@ -0,0 +1,47 @@ +#ifndef BENCHMARK_EXPORT_H +#define BENCHMARK_EXPORT_H + +#if defined(_WIN32) +#define EXPORT_ATTR __declspec(dllexport) +#define IMPORT_ATTR __declspec(dllimport) +#define NO_EXPORT_ATTR +#define DEPRECATED_ATTR __declspec(deprecated) +#else // _WIN32 +#define EXPORT_ATTR __attribute__((visibility("default"))) +#define IMPORT_ATTR __attribute__((visibility("default"))) +#define NO_EXPORT_ATTR __attribute__((visibility("hidden"))) +#define DEPRECATE_ATTR __attribute__((__deprecated__)) +#endif // _WIN32 + +#ifdef BENCHMARK_STATIC_DEFINE +#define BENCHMARK_EXPORT +#define BENCHMARK_NO_EXPORT +#else // BENCHMARK_STATIC_DEFINE +#ifndef BENCHMARK_EXPORT +#ifdef benchmark_EXPORTS +/* We are building this library */ +#define BENCHMARK_EXPORT EXPORT_ATTR +#else // benchmark_EXPORTS +/* We are using this library */ +#define BENCHMARK_EXPORT IMPORT_ATTR +#endif // benchmark_EXPORTS +#endif // !BENCHMARK_EXPORT + +#ifndef BENCHMARK_NO_EXPORT +#define BENCHMARK_NO_EXPORT NO_EXPORT_ATTR +#endif // !BENCHMARK_NO_EXPORT +#endif // BENCHMARK_STATIC_DEFINE + +#ifndef BENCHMARK_DEPRECATED +#define BENCHMARK_DEPRECATED DEPRECATE_ATTR +#endif // BENCHMARK_DEPRECATED + +#ifndef BENCHMARK_DEPRECATED_EXPORT +#define BENCHMARK_DEPRECATED_EXPORT BENCHMARK_EXPORT BENCHMARK_DEPRECATED +#endif // BENCHMARK_DEPRECATED_EXPORT + +#ifndef BENCHMARK_DEPRECATED_NO_EXPORT +#define BENCHMARK_DEPRECATED_NO_EXPORT BENCHMARK_NO_EXPORT BENCHMARK_DEPRECATED +#endif // BENCHMARK_DEPRECATED_EXPORT + +#endif /* BENCHMARK_EXPORT_H */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 05ea023853..3961f81640 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,9 +29,6 @@ target_include_directories(benchmark PUBLIC $ ) -generate_export_header(benchmark - EXPORT_FILE_NAME ${PROJECT_BINARY_DIR}/include/benchmark/export.h) - # libpfm, if available if (HAVE_LIBPFM) target_link_libraries(benchmark PRIVATE pfm) @@ -58,6 +55,10 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS") target_link_libraries(benchmark PRIVATE kstat) endif() +if (NOT BUILD_SHARED_LIBS) + add_definitions(-DBENCHMARK_STATIC_DEFINE) +endif() + # Benchmark main library add_library(benchmark_main "benchmark_main.cc") add_library(benchmark::benchmark_main ALIAS benchmark_main) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d528ee94a4..a49ab195e7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,6 +24,10 @@ if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) endforeach() endif() +if (NOT BUILD_SHARED_LIBS) + add_definitions(-DBENCHMARK_STATIC_DEFINE) +endif() + check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) set(BENCHMARK_O3_FLAG "") if (BENCHMARK_HAS_O3_FLAG) From e27c93073fd2c674077bf9dc915cd8c79b562156 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 21 Jul 2022 11:50:01 +0100 Subject: [PATCH 015/561] use target_compile_definitions (#1440) --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3961f81640..585cec6896 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,7 +32,7 @@ target_include_directories(benchmark PUBLIC # libpfm, if available if (HAVE_LIBPFM) target_link_libraries(benchmark PRIVATE pfm) - add_definitions(-DHAVE_LIBPFM) + target_compile_definitions(benchmark PRIVATE -DHAVE_LIBPFM) endif() # Link threads. @@ -56,7 +56,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS") endif() if (NOT BUILD_SHARED_LIBS) - add_definitions(-DBENCHMARK_STATIC_DEFINE) + target_compile_definitions(benchmark PRIVATE -DBENCHMARK_STATIC_DEFINE) endif() # Benchmark main library From ef7f75fb182fc23d03b4a3ecd09cc325ac125dfd Mon Sep 17 00:00:00 2001 From: maochongxin Date: Thu, 21 Jul 2022 19:34:02 +0800 Subject: [PATCH 016/561] simplified code (#1439) --- src/string_util.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/string_util.cc b/src/string_util.cc index 401fa13df7..b3196fc266 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -133,21 +133,21 @@ std::string StrFormatImp(const char* msg, va_list args) { // TODO(ericwf): use std::array for first attempt to avoid one memory // allocation guess what the size might be std::array local_buff; - std::size_t size = local_buff.size(); + // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation // in the android-ndk - auto ret = vsnprintf(local_buff.data(), size, msg, args_cp); + auto ret = vsnprintf(local_buff.data(), local_buff.size(), msg, args_cp); va_end(args_cp); // handle empty expansion if (ret == 0) return std::string{}; - if (static_cast(ret) < size) + if (static_cast(ret) < local_buff.size()) return std::string(local_buff.data()); // we did not provide a long enough buffer on our first attempt. // add 1 to size to account for null-byte in size cast to prevent overflow - size = static_cast(ret) + 1; + std::size_t size = static_cast(ret) + 1; auto buff_ptr = std::unique_ptr(new char[size]); // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation // in the android-ndk From 361e8d1cfe0c6c36d30b39f1b61302ece5507320 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 25 Jul 2022 12:35:38 +0100 Subject: [PATCH 017/561] version bump --- CMakeLists.txt | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a44613e960..2058effc70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ foreach(p endif() endforeach() -project (benchmark VERSION 1.6.2 LANGUAGES CXX) +project (benchmark VERSION 1.7.0 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 4d57c71732..b249ca8555 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -68,7 +68,7 @@ def my_benchmark(state): "State", ] -__version__ = "1.6.2" +__version__ = "1.7.0" class __OptionMaker: From 141b554e3a745da5216113cd5d00aea918fc7737 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 26 Jul 2022 04:00:49 -0400 Subject: [PATCH 018/561] Remove stray comment and added missing header (#1444) - The export.h is no longer generated, so removed the comment. - Added export.h to benchmark_main --- BUILD.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 1621504720..af18e3d7de 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -29,7 +29,7 @@ cc_library( ), hdrs = [ "include/benchmark/benchmark.h", - "include/benchmark/export.h", # From generate_export_header + "include/benchmark/export.h", ], linkopts = select({ ":windows": ["-DEFAULTLIB:shlwapi.lib"], @@ -47,7 +47,7 @@ cc_library( cc_library( name = "benchmark_main", srcs = ["src/benchmark_main.cc"], - hdrs = ["include/benchmark/benchmark.h"], + hdrs = ["include/benchmark/benchmark.h", "include/benchmark/export.h"], strip_include_prefix = "include", visibility = ["//visibility:public"], deps = [":benchmark"], From 892f29589dfe9bc253a3f3d50b4ce5ba240a5608 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Tue, 26 Jul 2022 22:33:32 +0700 Subject: [PATCH 019/561] Initialize help hook before actually parsing the command line (#1447) --- src/benchmark.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 6035491413..f8c0134370 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -678,9 +678,9 @@ void PrintDefaultHelp() { } void Initialize(int* argc, char** argv, void (*HelperPrintf)()) { + internal::HelperPrintf = HelperPrintf; internal::ParseCommandLineFlags(argc, argv); internal::LogLevel() = FLAGS_v; - internal::HelperPrintf = HelperPrintf; } void Shutdown() { delete internal::global_context; } From 7d48eff772e0f04761033a4ad2a004b4546df6f8 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Fri, 29 Jul 2022 15:18:19 +0100 Subject: [PATCH 020/561] remove unnecessary generated include directory (#1451) --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 585cec6896..1a6f073302 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,7 +26,6 @@ set_target_properties(benchmark PROPERTIES ) target_include_directories(benchmark PUBLIC $ - $ ) # libpfm, if available From 1cca1d091c52f2fe869da9a15dd4d39e84031a62 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Wed, 3 Aug 2022 04:44:35 -0400 Subject: [PATCH 021/561] Fixed build issues on window (#1449) * Fixed build issues on window - Added missing dlimport/export attributes in function definitions. (They are needed in both decls and defs) - Removed dlimport/dlexprt attribute in private field. (global_context is not exported anywhere). * fixed incorrect include path * undo changes w.r.t HelperPrintf * removed forward decl of private variable - instead, introduce a getter and use it. * Removed forward decl from benchmark_gtest too Co-authored-by: Dominic Hamon --- include/benchmark/benchmark.h | 2 ++ src/benchmark.cc | 6 +++++- src/benchmark_name.cc | 1 + src/check.cc | 2 +- src/commandlineflags.cc | 12 ++++++++++++ src/console_reporter.cc | 4 ++++ src/csv_reporter.cc | 3 +++ src/json_reporter.cc | 11 +++++------ src/reporter.cc | 10 +++++----- test/benchmark_gtest.cc | 5 ++++- 10 files changed, 42 insertions(+), 14 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index b25b001050..a17038c09c 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -417,6 +417,8 @@ class Benchmark; class BenchmarkImp; class BenchmarkFamilies; +BENCHMARK_EXPORT std::map*& GetGlobalContext(); + BENCHMARK_EXPORT void UseCharPointer(char const volatile*); diff --git a/src/benchmark.cc b/src/benchmark.cc index f8c0134370..e43b28d0cb 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -137,7 +137,11 @@ BM_DEFINE_int32(v, 0); namespace internal { -BENCHMARK_EXPORT std::map* global_context = nullptr; +std::map* global_context = nullptr; + +BENCHMARK_EXPORT std::map*& GetGlobalContext() { + return global_context; +} // FIXME: wouldn't LTO mess this up? void UseCharPointer(char const volatile*) {} diff --git a/src/benchmark_name.cc b/src/benchmark_name.cc index 4f7386068d..01676bbc84 100644 --- a/src/benchmark_name.cc +++ b/src/benchmark_name.cc @@ -51,6 +51,7 @@ std::string join(char delimiter, const Ts&... ts) { } } // namespace +BENCHMARK_EXPORT std::string BenchmarkName::str() const { return join('/', function_name, args, min_time, min_warmup_time, iterations, repetitions, time_type, threads); diff --git a/src/check.cc b/src/check.cc index 422b9483a8..5f7526e08d 100644 --- a/src/check.cc +++ b/src/check.cc @@ -5,7 +5,7 @@ namespace internal { static AbortHandlerT* handler = &std::abort; -AbortHandlerT*& GetAbortHandler() { return handler; } +BENCHMARK_EXPORT AbortHandlerT*& GetAbortHandler() { return handler; } } // namespace internal } // namespace benchmark diff --git a/src/commandlineflags.cc b/src/commandlineflags.cc index 9615e351ff..1f555b2757 100644 --- a/src/commandlineflags.cc +++ b/src/commandlineflags.cc @@ -121,12 +121,14 @@ static std::string FlagToEnvVar(const char* flag) { } // namespace +BENCHMARK_EXPORT bool BoolFromEnv(const char* flag, bool default_val) { const std::string env_var = FlagToEnvVar(flag); const char* const value_str = getenv(env_var.c_str()); return value_str == nullptr ? default_val : IsTruthyFlagValue(value_str); } +BENCHMARK_EXPORT int32_t Int32FromEnv(const char* flag, int32_t default_val) { const std::string env_var = FlagToEnvVar(flag); const char* const value_str = getenv(env_var.c_str()); @@ -139,6 +141,7 @@ int32_t Int32FromEnv(const char* flag, int32_t default_val) { return value; } +BENCHMARK_EXPORT double DoubleFromEnv(const char* flag, double default_val) { const std::string env_var = FlagToEnvVar(flag); const char* const value_str = getenv(env_var.c_str()); @@ -151,12 +154,14 @@ double DoubleFromEnv(const char* flag, double default_val) { return value; } +BENCHMARK_EXPORT const char* StringFromEnv(const char* flag, const char* default_val) { const std::string env_var = FlagToEnvVar(flag); const char* const value = getenv(env_var.c_str()); return value == nullptr ? default_val : value; } +BENCHMARK_EXPORT std::map KvPairsFromEnv( const char* flag, std::map default_val) { const std::string env_var = FlagToEnvVar(flag); @@ -201,6 +206,7 @@ const char* ParseFlagValue(const char* str, const char* flag, return flag_end + 1; } +BENCHMARK_EXPORT bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); @@ -213,6 +219,7 @@ bool ParseBoolFlag(const char* str, const char* flag, bool* value) { return true; } +BENCHMARK_EXPORT bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -225,6 +232,7 @@ bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { value); } +BENCHMARK_EXPORT bool ParseDoubleFlag(const char* str, const char* flag, double* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -237,6 +245,7 @@ bool ParseDoubleFlag(const char* str, const char* flag, double* value) { value); } +BENCHMARK_EXPORT bool ParseStringFlag(const char* str, const char* flag, std::string* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -248,6 +257,7 @@ bool ParseStringFlag(const char* str, const char* flag, std::string* value) { return true; } +BENCHMARK_EXPORT bool ParseKeyValueFlag(const char* str, const char* flag, std::map* value) { const char* const value_str = ParseFlagValue(str, flag, false); @@ -263,10 +273,12 @@ bool ParseKeyValueFlag(const char* str, const char* flag, return true; } +BENCHMARK_EXPORT bool IsFlag(const char* str, const char* flag) { return (ParseFlagValue(str, flag, true) != nullptr); } +BENCHMARK_EXPORT bool IsTruthyFlagValue(const std::string& value) { if (value.size() == 1) { char v = value[0]; diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 1711356b9b..3950e49814 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -33,6 +33,7 @@ namespace benchmark { +BENCHMARK_EXPORT bool ConsoleReporter::ReportContext(const Context& context) { name_field_width_ = context.name_field_width; printed_header_ = false; @@ -52,6 +53,7 @@ bool ConsoleReporter::ReportContext(const Context& context) { return true; } +BENCHMARK_EXPORT void ConsoleReporter::PrintHeader(const Run& run) { std::string str = FormatString("%-*s %13s %15s %12s", static_cast(name_field_width_), @@ -69,6 +71,7 @@ void ConsoleReporter::PrintHeader(const Run& run) { GetOutputStream() << line << "\n" << str << "\n" << line << "\n"; } +BENCHMARK_EXPORT void ConsoleReporter::ReportRuns(const std::vector& reports) { for (const auto& run : reports) { // print the header: @@ -120,6 +123,7 @@ static std::string FormatTime(double time) { return FormatString("%10.0f", time); } +BENCHMARK_EXPORT void ConsoleReporter::PrintRunData(const Run& result) { typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...); auto& Out = GetOutputStream(); diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 1c5e9fa668..83c94573f5 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -52,11 +52,13 @@ std::string CsvEscape(const std::string& s) { return '"' + tmp + '"'; } +BENCHMARK_EXPORT bool CSVReporter::ReportContext(const Context& context) { PrintBasicContext(&GetErrorStream(), context); return true; } +BENCHMARK_EXPORT void CSVReporter::ReportRuns(const std::vector& reports) { std::ostream& Out = GetOutputStream(); @@ -103,6 +105,7 @@ void CSVReporter::ReportRuns(const std::vector& reports) { } } +BENCHMARK_EXPORT void CSVReporter::PrintRunData(const Run& run) { std::ostream& Out = GetOutputStream(); Out << CsvEscape(run.benchmark_name()) << ","; diff --git a/src/json_reporter.cc b/src/json_reporter.cc index e9999e18ac..d55a0e6f0b 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -28,10 +28,6 @@ #include "timers.h" namespace benchmark { -namespace internal { -extern std::map* global_context; -} - namespace { std::string StrEscape(const std::string& s) { @@ -178,8 +174,11 @@ bool JSONReporter::ReportContext(const Context& context) { #endif out << indent << FormatKV("library_build_type", build_type); - if (internal::global_context != nullptr) { - for (const auto& kv : *internal::global_context) { + std::map* global_context = + internal::GetGlobalContext(); + + if (global_context != nullptr) { + for (const auto& kv : *global_context) { out << ",\n"; out << indent << FormatKV(kv.first, kv.second); } diff --git a/src/reporter.cc b/src/reporter.cc index 1d2df17b90..8b5fdaff65 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -25,9 +25,6 @@ #include "timers.h" namespace benchmark { -namespace internal { -extern std::map *global_context; -} BenchmarkReporter::BenchmarkReporter() : output_stream_(&std::cout), error_stream_(&std::cerr) {} @@ -67,8 +64,11 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, Out << "\n"; } - if (internal::global_context != nullptr) { - for (const auto &kv : *internal::global_context) { + std::map *global_context = + internal::GetGlobalContext(); + + if (global_context != nullptr) { + for (const auto &kv : *global_context) { Out << kv.first << ": " << kv.second << "\n"; } } diff --git a/test/benchmark_gtest.cc b/test/benchmark_gtest.cc index cfc0a0f70f..3873128e9f 100644 --- a/test/benchmark_gtest.cc +++ b/test/benchmark_gtest.cc @@ -8,7 +8,6 @@ namespace benchmark { namespace internal { -BENCHMARK_EXPORT extern std::map* global_context; namespace { @@ -134,6 +133,8 @@ TEST(AddRangeTest, Simple8) { } TEST(AddCustomContext, Simple) { + std::map *&global_context = + internal::GetGlobalContext(); EXPECT_THAT(global_context, nullptr); AddCustomContext("foo", "bar"); @@ -148,6 +149,8 @@ TEST(AddCustomContext, Simple) { } TEST(AddCustomContext, DuplicateKey) { + std::map *&global_context = + internal::GetGlobalContext(); EXPECT_THAT(global_context, nullptr); AddCustomContext("foo", "bar"); From 5eb16eebb3ca8dabb64720fca2fc491bf4f87b6b Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Thu, 4 Aug 2022 04:18:19 -0400 Subject: [PATCH 022/561] Explicitly cast int literals to int8_t in tests to silence implicit-conversion warnings (#1455) * Explicitly cast int literals to int8_t in tests so silence implicit-conversion warnings Error came from: ``` : error: implicit conversion loses integer precision: 'const int' to 'const signed char' [-Werror,-Wimplicit-int-conversion] ``` * clang format * undo deleted line --- test/benchmark_gtest.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/benchmark_gtest.cc b/test/benchmark_gtest.cc index 3873128e9f..a6919be3a0 100644 --- a/test/benchmark_gtest.cc +++ b/test/benchmark_gtest.cc @@ -37,8 +37,9 @@ TEST(AddRangeTest, Advanced64) { TEST(AddRangeTest, FullRange8) { std::vector dst; - AddRange(&dst, int8_t{1}, std::numeric_limits::max(), 8); - EXPECT_THAT(dst, testing::ElementsAre(1, 8, 64, 127)); + AddRange(&dst, int8_t{1}, std::numeric_limits::max(), int8_t{8}); + EXPECT_THAT( + dst, testing::ElementsAre(int8_t{1}, int8_t{8}, int8_t{64}, int8_t{127})); } TEST(AddRangeTest, FullRange64) { @@ -128,8 +129,9 @@ TEST(AddRangeTest, FullNegativeRange64) { TEST(AddRangeTest, Simple8) { std::vector dst; - AddRange(&dst, 1, 8, 2); - EXPECT_THAT(dst, testing::ElementsAre(1, 2, 4, 8)); + AddRange(&dst, int8_t{1}, int8_t{8}, int8_t{2}); + EXPECT_THAT(dst, + testing::ElementsAre(int8_t{1}, int8_t{2}, int8_t{4}, int8_t{8})); } TEST(AddCustomContext, Simple) { From 974cd5a5c5a78e76ebc50961f4dbf3bf6d4ade4e Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 4 Aug 2022 15:33:35 +0100 Subject: [PATCH 023/561] Ensure we don't need benchmark installed to pass c++ feature checks (#1456) * Ensure we don't need benchmark installed to pass c++ feature checks Requires removal of some dependencies on benchmark.h from internal low-level headers, which is a good thing. Also added better logging to the feature check cmake module. --- CMakeLists.txt | 2 +- cmake/CXXFeatureCheck.cmake | 11 ++++++----- include/benchmark/benchmark.h | 11 ----------- src/benchmark_register.h | 1 + src/check.h | 17 +++++++++++++++++ src/internal_macros.h | 2 -- src/log.h | 26 ++++++++++++++++++++------ src/string_util.h | 2 ++ test/benchmark_gtest.cc | 7 +++---- 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2058effc70..3d636bea75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,7 +223,7 @@ else() add_cxx_compiler_flag(-wd654) add_cxx_compiler_flag(-Wthread-safety) if (HAVE_CXX_FLAG_WTHREAD_SAFETY) - cxx_feature_check(THREAD_SAFETY_ATTRIBUTES) + cxx_feature_check(THREAD_SAFETY_ATTRIBUTES "-DINCLUDE_DIRECTORIES=${PROJECT_SOURCE_DIR}/include") endif() # On most UNIX like platforms g++ and clang++ define _GNU_SOURCE as a diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index aa67f58e6d..a96a014fb4 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -27,17 +27,18 @@ function(cxx_feature_check FILE) return() endif() + set(FEATURE_CHECK_CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}) if (ARGC GREATER 1) message(STATUS "Enabling additional flags: ${ARGV1}") - list(APPEND BENCHMARK_CXX_LINKER_FLAGS ${ARGV1}) + list(APPEND FEATURE_CHECK_CMAKE_FLAGS ${ARGV1}) endif() if (NOT DEFINED COMPILE_${FEATURE}) - message(STATUS "Performing Test ${FEATURE}") if(CMAKE_CROSSCOMPILING) + message(STATUS "Cross-compiling to test ${FEATURE}") try_compile(COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS} + CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) if(COMPILE_${FEATURE}) @@ -48,10 +49,10 @@ function(cxx_feature_check FILE) set(RUN_${FEATURE} 1 CACHE INTERNAL "") endif() else() - message(STATUS "Performing Test ${FEATURE}") + message(STATUS "Compiling and running to test ${FEATURE}") try_run(RUN_${FEATURE} COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS} + CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) endif() diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index a17038c09c..f0152e5a6a 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -220,22 +220,11 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #if defined(__GNUC__) || defined(__clang__) #define BENCHMARK_ALWAYS_INLINE __attribute__((always_inline)) -#define BENCHMARK_NOEXCEPT noexcept -#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) #elif defined(_MSC_VER) && !defined(__clang__) #define BENCHMARK_ALWAYS_INLINE __forceinline -#if _MSC_VER >= 1900 -#define BENCHMARK_NOEXCEPT noexcept -#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) -#else -#define BENCHMARK_NOEXCEPT -#define BENCHMARK_NOEXCEPT_OP(x) -#endif #define __func__ __FUNCTION__ #else #define BENCHMARK_ALWAYS_INLINE -#define BENCHMARK_NOEXCEPT -#define BENCHMARK_NOEXCEPT_OP(x) #endif #define BENCHMARK_INTERNAL_TOSTRING2(x) #x diff --git a/src/benchmark_register.h b/src/benchmark_register.h index a5a250cc70..53367c707c 100644 --- a/src/benchmark_register.h +++ b/src/benchmark_register.h @@ -1,6 +1,7 @@ #ifndef BENCHMARK_REGISTER_H #define BENCHMARK_REGISTER_H +#include #include #include diff --git a/src/check.h b/src/check.h index 1129e81402..c1cd5e85e4 100644 --- a/src/check.h +++ b/src/check.h @@ -9,6 +9,23 @@ #include "internal_macros.h" #include "log.h" +#if defined(__GNUC__) || defined(__clang__) +#define BENCHMARK_NOEXCEPT noexcept +#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) +#elif defined(_MSC_VER) && !defined(__clang__) +#if _MSC_VER >= 1900 +#define BENCHMARK_NOEXCEPT noexcept +#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) +#else +#define BENCHMARK_NOEXCEPT +#define BENCHMARK_NOEXCEPT_OP(x) +#endif +#define __func__ __FUNCTION__ +#else +#define BENCHMARK_NOEXCEPT +#define BENCHMARK_NOEXCEPT_OP(x) +#endif + namespace benchmark { namespace internal { diff --git a/src/internal_macros.h b/src/internal_macros.h index 72ba54bad2..1fe1eb6a23 100644 --- a/src/internal_macros.h +++ b/src/internal_macros.h @@ -1,8 +1,6 @@ #ifndef BENCHMARK_INTERNAL_MACROS_H_ #define BENCHMARK_INTERNAL_MACROS_H_ -#include "benchmark/benchmark.h" - /* Needed to detect STL */ #include diff --git a/src/log.h b/src/log.h index 48c071aded..45701667a2 100644 --- a/src/log.h +++ b/src/log.h @@ -4,7 +4,12 @@ #include #include -#include "benchmark/benchmark.h" +// NOTE: this is also defined in benchmark.h but we're trying to avoid a +// dependency. +// The _MSVC_LANG check should detect Visual Studio 2015 Update 3 and newer. +#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) +#define BENCHMARK_HAS_CXX11 +#endif namespace benchmark { namespace internal { @@ -23,7 +28,16 @@ class LogType { private: LogType(std::ostream* out) : out_(out) {} std::ostream* out_; - BENCHMARK_DISALLOW_COPY_AND_ASSIGN(LogType); + + // NOTE: we could use BENCHMARK_DISALLOW_COPY_AND_ASSIGN but we shouldn't have + // a dependency on benchmark.h from here. +#ifndef BENCHMARK_HAS_CXX11 + LogType(const LogType&); + LogType& operator=(const LogType&); +#else + LogType(const LogType&) = delete; + LogType& operator=(const LogType&) = delete; +#endif }; template @@ -47,13 +61,13 @@ inline int& LogLevel() { } inline LogType& GetNullLogInstance() { - static LogType log(nullptr); - return log; + static LogType null_log((std::ostream*)nullptr); + return null_log; } inline LogType& GetErrorLogInstance() { - static LogType log(&std::clog); - return log; + static LogType error_log(&std::clog); + return error_log; } inline LogType& GetLogInstanceForLevel(int level) { diff --git a/src/string_util.h b/src/string_util.h index 4145861835..37bdd2e980 100644 --- a/src/string_util.h +++ b/src/string_util.h @@ -4,8 +4,10 @@ #include #include #include +#include #include "benchmark/export.h" +#include "check.h" #include "internal_macros.h" namespace benchmark { diff --git a/test/benchmark_gtest.cc b/test/benchmark_gtest.cc index a6919be3a0..2c9e555d92 100644 --- a/test/benchmark_gtest.cc +++ b/test/benchmark_gtest.cc @@ -3,6 +3,7 @@ #include #include "../src/benchmark_register.h" +#include "benchmark/benchmark.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -135,8 +136,7 @@ TEST(AddRangeTest, Simple8) { } TEST(AddCustomContext, Simple) { - std::map *&global_context = - internal::GetGlobalContext(); + std::map *&global_context = GetGlobalContext(); EXPECT_THAT(global_context, nullptr); AddCustomContext("foo", "bar"); @@ -151,8 +151,7 @@ TEST(AddCustomContext, Simple) { } TEST(AddCustomContext, DuplicateKey) { - std::map *&global_context = - internal::GetGlobalContext(); + std::map *&global_context = GetGlobalContext(); EXPECT_THAT(global_context, nullptr); AddCustomContext("foo", "bar"); From a476d0fd8e5d71a3b865d1ae9e0bfd7b4b2d5aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cezary=20Skrzy=C5=84ski?= Date: Mon, 8 Aug 2022 16:57:48 +0200 Subject: [PATCH 024/561] Avoid deprecation warning in NVHPC (#1459) * Avoid deprecation warning in NVHPC * Use more general NVCC identification macro --- include/benchmark/benchmark.h | 2 +- src/benchmark.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index f0152e5a6a..0eddc5409b 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -231,7 +231,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #define BENCHMARK_INTERNAL_TOSTRING(x) BENCHMARK_INTERNAL_TOSTRING2(x) // clang-format off -#if defined(__GNUC__) || defined(__clang__) +#if defined(__GNUC__) && !defined(__NVCC__) || defined(__clang__) #define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) #define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) #define BENCHMARK_DISABLE_DEPRECATED_WARNING \ diff --git a/src/benchmark.cc b/src/benchmark.cc index e43b28d0cb..f18c30810f 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -182,7 +182,7 @@ State::State(IterationCount max_iters, const std::vector& ranges, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Winvalid-offsetof" #endif -#if defined(__CUDACC__) +#if defined(__NVCC__) #pragma nv_diagnostic push #pragma nv_diag_suppress 1427 #endif @@ -196,7 +196,7 @@ State::State(IterationCount max_iters, const std::vector& ranges, #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif -#if defined(__CUDACC__) +#if defined(__NVCC__) #pragma nv_diagnostic pop #endif } From af32e3fe1aa48ebc831ec099e394ce9f38f8daf5 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 8 Aug 2022 13:34:20 -0700 Subject: [PATCH 025/561] run ClearRegisteredBenchmarks at exit (#1463) --- bindings/python/google_benchmark/__init__.py | 2 ++ bindings/python/google_benchmark/benchmark.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index b249ca8555..3dfabfb344 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -26,6 +26,7 @@ def my_benchmark(state): if __name__ == '__main__': benchmark.main() """ +import atexit from absl import app from google_benchmark import _benchmark @@ -158,3 +159,4 @@ def main(argv=None): # Methods for use with custom main function. initialize = _benchmark.Initialize run_benchmarks = _benchmark.RunSpecifiedBenchmarks +atexit.register(_benchmark.ClearRegisteredBenchmarks) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index ea40990e08..5614b92817 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -179,5 +179,6 @@ PYBIND11_MODULE(_benchmark, m) { py::return_value_policy::reference); m.def("RunSpecifiedBenchmarks", []() { benchmark::RunSpecifiedBenchmarks(); }); + m.def("ClearRegisteredBenchmarks", benchmark::ClearRegisteredBenchmarks); }; } // namespace From 4366d663856615716cfeeba781b3ac9cb9df9596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Daase?= Date: Wed, 10 Aug 2022 18:46:55 +0200 Subject: [PATCH 026/561] FIx typo in benchmark.h (#1465) --- include/benchmark/benchmark.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 0eddc5409b..bc426ca3e1 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1107,7 +1107,7 @@ class BENCHMARK_EXPORT Benchmark { // By default, the CPU time is measured only for the main thread, which may // be unrepresentative if the benchmark uses threads internally. If called, // the total CPU time spent by all the threads will be measured instead. - // By default, the only the main thread CPU time will be measured. + // By default, only the main thread CPU time will be measured. Benchmark* MeasureProcessCPUTime(); // If a particular benchmark should use the Wall clock instead of the CPU time From 77d1e74d29d4ee309b1c08eaea40ad789f08d125 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 10 Aug 2022 12:42:27 -0700 Subject: [PATCH 027/561] add debug option for enabling more output for failed cxxfeaturechecks (#1467) fixes #1466 --- cmake/CXXFeatureCheck.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index a96a014fb4..50e5f680b5 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -17,6 +17,8 @@ if(__cxx_feature_check) endif() set(__cxx_feature_check INCLUDED) +option(CXXFEATURECHECK_DEBUG OFF) + function(cxx_feature_check FILE) string(TOLOWER ${FILE} FILE) string(TOUPPER ${FILE} VAR) @@ -64,7 +66,11 @@ function(cxx_feature_check FILE) add_definitions(-DHAVE_${VAR}) else() if(NOT COMPILE_${FEATURE}) - message(STATUS "Performing Test ${FEATURE} -- failed to compile: ${COMPILE_OUTPUT_VAR}") + if(CXXFEATURECHECK_DEBUG) + message(STATUS "Performing Test ${FEATURE} -- failed to compile: ${COMPILE_OUTPUT_VAR}") + else() + message(STATUS "Performing Test ${FEATURE} -- failed to compile") + endif() else() message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run") endif() From e8baf2622591569a27615b31372d1e9cc046af10 Mon Sep 17 00:00:00 2001 From: "Pavel V. Sysolyatin" Date: Thu, 18 Aug 2022 17:19:51 +0700 Subject: [PATCH 028/561] Link error when use as static library on windows. (#1470) --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a6f073302..55402e6585 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,7 +55,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS") endif() if (NOT BUILD_SHARED_LIBS) - target_compile_definitions(benchmark PRIVATE -DBENCHMARK_STATIC_DEFINE) + target_compile_definitions(benchmark PUBLIC -DBENCHMARK_STATIC_DEFINE) endif() # Benchmark main library From 2a78e8cbe9b104834d96c78ccc9f9513a29f8c71 Mon Sep 17 00:00:00 2001 From: babbaj Date: Tue, 23 Aug 2022 16:28:02 -0400 Subject: [PATCH 029/561] use CMAKE_INSTALL_FULL in pkg-config file (#1473) --- cmake/benchmark.pc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/benchmark.pc.in b/cmake/benchmark.pc.in index 34beb012ee..9dae881c79 100644 --- a/cmake/benchmark.pc.in +++ b/cmake/benchmark.pc.in @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} -libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ -includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: Google microbenchmark framework From 13196fff8452aae3bcd9af6eb35f957f3677907d Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Sat, 27 Aug 2022 10:41:33 -0700 Subject: [PATCH 030/561] Clean up test documentation formatting (#1475) --- test/reporter_output_test.cc | 2 +- test/user_counters_test.cc | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 65bb14a171..823dca41a1 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -318,7 +318,7 @@ ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_no_arg_name/3\",$"}, ADD_CASES(TC_CSVOut, {{"^\"BM_no_arg_name/3\",%csv_report$"}}); // ========================================================================= // -// ------------------------ Testing Arg Name Output ----------------------- // +// ------------------------ Testing Arg Name Output ------------------------ // // ========================================================================= // void BM_arg_name(benchmark::State& state) { diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index 1cc74552a1..f4be7ebb32 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -195,8 +195,7 @@ void CheckInvert(Results const& e) { CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert); // ========================================================================= // -// ------------------------- InvertedRate Counters Output -// -------------------------- // +// --------------------- InvertedRate Counters Output ---------------------- // // ========================================================================= // void BM_Counters_InvertedRate(benchmark::State& state) { @@ -460,7 +459,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_kIsIterationInvariantRate", &CheckIsIterationInvariantRate); // ========================================================================= // -// ------------------- AvgIterations Counters Output ------------------ // +// --------------------- AvgIterations Counters Output --------------------- // // ========================================================================= // void BM_Counters_AvgIterations(benchmark::State& state) { @@ -502,7 +501,7 @@ void CheckAvgIterations(Results const& e) { CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations", &CheckAvgIterations); // ========================================================================= // -// ----------------- AvgIterationsRate Counters Output ---------------- // +// ------------------- AvgIterationsRate Counters Output ------------------- // // ========================================================================= // void BM_Counters_kAvgIterationsRate(benchmark::State& state) { From ff629d847c4c4012b6a68c335e74b5e5ede269b3 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 30 Aug 2022 14:35:50 +0200 Subject: [PATCH 031/561] Enable aarch64 Linux wheel builds, use cibuildwheel action directly (#1472) This commit enables arm64 Linux wheel builds for Python. It also changes the build procedure on Linux using cibuildwheel in GitHub Actions. Instead of the more granular, verbose approach that was used until now, we opt for the GitHub Action released by cibuildwheel directly. We also change the Bazel install procedure in the manylinux Docker container image. Previously, Bazel was installed from an added RHEL repo, since that is the recommended official way of installing Bazel on CentOS platforms. However, the last successful build available for manylinux2014 has been Bazel 4, which is showing its age with the release of Bazel 6 coming up as of this commit. After this change, prebuilt Bazel binaries are downloaded using wget directly from the Bazel GitHub release page. Since Bazel is built for both x86 and arm64 on Linux, we immediately gain wheel build support for these architectures. However, since the architecture of the manylinux image is aarch64 instead of arm64, a shell script was added that normalizes aarch64 to arm64, and installs the correct arm64 Bazel binary if necessary. --- .github/install_bazel.sh | 13 +++++++++++++ .github/workflows/wheels.yml | 22 +++++++++------------- 2 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 .github/install_bazel.sh diff --git a/.github/install_bazel.sh b/.github/install_bazel.sh new file mode 100644 index 0000000000..afdd8db8ac --- /dev/null +++ b/.github/install_bazel.sh @@ -0,0 +1,13 @@ +if ! bazel version; then + arch=$(uname -m) + if [ "$arch" == "aarch64" ]; then + arch="arm64" + fi + echo "Installing wget and downloading $arch Bazel binary from GitHub releases." + yum install -y wget + wget "https://github.com/bazelbuild/bazel/releases/download/5.2.0/bazel-5.2.0-linux-$arch" -O /usr/local/bin/bazel + chmod +x /usr/local/bin/bazel +else + # bazel is installed for the correct architecture + exit 0 +fi diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 6c2256970b..aeea3b15e5 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -39,27 +39,23 @@ jobs: - name: Check out Google Benchmark uses: actions/checkout@v3 - - name: Set up Python 3.9 - uses: actions/setup-python@v3 + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v2 with: - python-version: 3.9 + platforms: all - - name: Install and run cibuildwheel on ${{ matrix.os }} + - name: Build wheels on ${{ matrix.os }} using cibuildwheel + uses: pypa/cibuildwheel@v2.9.0 env: CIBW_BUILD: 'cp37-* cp38-* cp39-* cp310-*' CIBW_SKIP: "cp37-*-arm64 *-musllinux_*" - # TODO: Build ppc64le, aarch64 using some other trick - CIBW_ARCHS_LINUX: x86_64 + # TODO: Build ppc64le using some other trick + CIBW_ARCHS_LINUX: x86_64 aarch64 CIBW_ARCHS_MACOS: x86_64 arm64 CIBW_ARCHS_WINDOWS: AMD64 - CIBW_BEFORE_ALL_LINUX: > - curl -O --retry-delay 5 --retry 5 https://copr.fedorainfracloud.org/coprs/vbatts/bazel/repo/epel-7/vbatts-bazel-epel-7.repo && - cp vbatts-bazel-epel-7.repo /etc/yum.repos.d/bazel.repo && - yum install -y bazel4 + CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py - run: | - pip install cibuildwheel - python -m cibuildwheel --output-dir wheelhouse - name: Upload Google Benchmark ${{ matrix.os }} wheels uses: actions/upload-artifact@v3 From db55c89f31385f8105f56ac8245a51777e94a628 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 30 Aug 2022 10:32:46 -0400 Subject: [PATCH 032/561] Eliminate usage of deprecated API in sysinfo.cc (#1474) * Eliminate usage of deprecated API in sysinfo.cc The `std::wstring_convert` is deprecated in C++17. Since this code is in the windows branch, we could use the win32 API (MultiByteToWideChar) * ran clang-format --- src/sysinfo.cc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 8e536905b8..b91739b1e3 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -417,11 +417,19 @@ std::string GetSystemName() { #ifndef UNICODE str = std::string(hostname, DWCOUNT); #else - // Using wstring_convert, Is deprecated in C++17 - using convert_type = std::codecvt_utf8; - std::wstring_convert converter; - std::wstring wStr(hostname, DWCOUNT); - str = converter.to_bytes(wStr); + std::vector converted; + // Find the length first. + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname, + DWCOUNT, converted.begin(), 0); + // TODO: Report error from GetLastError()? + if (len == 0) return std::string(""); + converted.reserve(len + 1); + + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname, DWCOUNT, + converted.begin(), converted.size()); + // TODO: Report error from GetLastError()? + if (len == 0) return std::string(""); + str = std::string(converted.data()); #endif return str; #else // defined(BENCHMARK_OS_WINDOWS) From becf80f3a98d42e07823d7dcdfb611e2ccbaf035 Mon Sep 17 00:00:00 2001 From: Matt Armstrong Date: Thu, 8 Sep 2022 10:26:58 -0700 Subject: [PATCH 033/561] Stop using pandas.Timedelta (fixes #1482) (#1483) The pandas.Timedelta class truncates to integral nanoseconds, which throws away sub-nanosecond precision present in benchmark JSON. Switch to floating point multiplication, which preserves it. Fixes #1482 Tentatively fixes #1477. --- requirements.txt | 1 - tools/gbench/report.py | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index 18def0ee3e..1c8a4bd123 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ numpy == 1.22 scipy == 1.5.4 -pandas == 1.1.5 diff --git a/tools/gbench/report.py b/tools/gbench/report.py index 4f2ea3ef5e..b2bbfb9f62 100644 --- a/tools/gbench/report.py +++ b/tools/gbench/report.py @@ -9,7 +9,6 @@ from scipy.stats import mannwhitneyu, gmean from numpy import array -from pandas import Timedelta class BenchmarkColor(object): @@ -43,6 +42,13 @@ def __format__(self, format): UTEST_OPTIMAL_REPETITIONS = 9 # Lowest reasonable number, More is better. UTEST_COL_NAME = "_pvalue" +_TIME_UNIT_TO_SECONDS_MULTIPLIER = { + "s": 1.0, + "ms": 1e-3, + "us": 1e-6, + "ns": 1e-9, +} + def color_format(use_color, fmt_str, *args, **kwargs): """ @@ -157,9 +163,9 @@ def get_timedelta_field_as_seconds(benchmark, field_name): Get value of field_name field of benchmark, which is time with time unit time_unit, as time in seconds. """ - time_unit = benchmark['time_unit'] if 'time_unit' in benchmark else 's' - dt = Timedelta(benchmark[field_name], time_unit) - return dt / Timedelta(1, 's') + timedelta = benchmark[field_name] + time_unit = benchmark.get('time_unit', 's') + return timedelta * _TIME_UNIT_TO_SECONDS_MULTIPLIER.get(time_unit) def calculate_geomean(json): @@ -454,7 +460,7 @@ def test_json_diff_report_pretty_printing(self): ['BM_ThirdFaster', '-0.3333', '-0.3334', '100', '67', '100', '67'], ['BM_NotBadTimeUnit', '-0.9000', '+0.2000', '0', '0', '0', '1'], ['BM_hasLabel', '+0.0000', '+0.0000', '1', '1', '1', '1'], - ['OVERALL_GEOMEAN', '-0.8117', '-0.7783', '0', '0', '0', '0'] + ['OVERALL_GEOMEAN', '-0.8113', '-0.7779', '0', '0', '0', '0'] ] output_lines_with_header = print_difference_report( self.json_diff_report, use_color=False) @@ -591,7 +597,7 @@ def test_json_diff_report_output(self): 'label': '', 'measurements': [{'real_time': 3.1622776601683826e-06, 'cpu_time': 3.2130844755623912e-06, 'real_time_other': 1.9768988699420897e-07, 'cpu_time_other': 2.397447755209533e-07, - 'time': -0.8117033010153573, 'cpu': -0.7783324768278522}], + 'time': -0.8112976497120911, 'cpu': -0.7778551721181174}], 'time_unit': 's', 'run_type': 'aggregate', 'aggregate_name': 'geomean', 'utest': {} From 1c26d8a3371dfd988223c6b86e3397751ded1f7c Mon Sep 17 00:00:00 2001 From: Matt Armstrong Date: Fri, 9 Sep 2022 07:41:10 -0700 Subject: [PATCH 034/561] Discuss sources of variance in the user guide (#1481) * Discuss sources of variance in the user guide * Mention cpufreq/boost * Pull variance material into a new document Add reducing_variance.md as a place to discuss things related to variance and, in the future, statistical interpretation of benchmark results. Co-authored-by: Dominic Hamon --- docs/reducing_variance.md | 100 ++++++++++++++++++++++++++++++++++++++ docs/user_guide.md | 37 +++----------- 2 files changed, 106 insertions(+), 31 deletions(-) create mode 100644 docs/reducing_variance.md diff --git a/docs/reducing_variance.md b/docs/reducing_variance.md new file mode 100644 index 0000000000..f8b757580d --- /dev/null +++ b/docs/reducing_variance.md @@ -0,0 +1,100 @@ +# Reducing Variance + + + +## Disabling CPU Frequency Scaling + +If you see this error: + +``` +***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead. +``` + +you might want to disable the CPU frequency scaling while running the +benchmark, as well as consider other ways to stabilize the performance of +your system while benchmarking. + +See [Reducing Variance](reducing_variance.md) for more information. + +Exactly how to do this depends on the Linux distribution, +desktop environment, and installed programs. Specific details are a moving +target, so we will not attempt to exhaustively document them here. + +One simple option is to use the `cpupower` program to change the +performance governor to "performance". This tool is maintained along with +the Linux kernel and provided by your distribution. + +It must be run as root, like this: + +```bash +sudo cpupower frequency-set --governor performance +``` + +After this you can verify that all CPUs are using the performance governor +by running this command: + +```bash +cpupower frequency-info -o proc +``` + +The benchmarks you subsequently run will have less variance. + + + +## Reducing Variance in Benchmarks + +The Linux CPU frequency governor [discussed +above](user_guide#disabling-cpu-frequency-scaling) is not the only source +of noise in benchmarks. Some, but not all, of the sources of variance +include: + +1. On multi-core machines not all CPUs/CPU cores/CPU threads run the same + speed, so running a benchmark one time and then again may give a + different result depending on which CPU it ran on. +2. CPU scaling features that run on the CPU, like Intel's Turbo Boost and + AMD Turbo Core and Precision Boost, can temporarily change the CPU + frequency even when the using the "performance" governor on Linux. +3. Context switching between CPUs, or scheduling competition on the CPU the + benchmark is running on. +4. Intel Hyperthreading or AMD SMT causing the same issue as above. +5. Cache effects caused by code running on other CPUs. +6. Non-uniform memory architectures (NUMA). + +These can cause variance in benchmarks results within a single run +(`--benchmark_repetitions=N`) or across multiple runs of the benchmark +program. + +Reducing sources of variance is OS and architecture dependent, which is one +reason some companies maintain machines dedicated to performance testing. + +Some of the easier and and effective ways of reducing variance on a typical +Linux workstation are: + +1. Use the performance governer as [discussed +above](user_guide#disabling-cpu-frequency-scaling). +1. Disable processor boosting by: + ```sh + echo 0 | sudo tee /sys/devices/system/cpu/cpufreq/boost + ``` + See the Linux kernel's + [boost.txt](https://www.kernel.org/doc/Documentation/cpu-freq/boost.txt) + for more information. +2. Set the benchmark program's task affinity to a fixed cpu. For example: + ```sh + taskset -c 0 ./mybenchmark + ``` +3. Disabling Hyperthreading/SMT. This can be done in the Bios or using the + `/sys` file system (see the LLVM project's [Benchmarking + tips](https://llvm.org/docs/Benchmarking.html)). +4. Close other programs that do non-trivial things based on timers, such as + your web browser, desktop environment, etc. +5. Reduce the working set of your benchmark to fit within the L1 cache, but + do be aware that this may lead you to optimize for an unrelistic + situation. + +Further resources on this topic: + +1. The LLVM project's [Benchmarking + tips](https://llvm.org/docs/Benchmarking.html). +1. The Arch Wiki [Cpu frequency +scaling](https://wiki.archlinux.org/title/CPU_frequency_scaling) page. diff --git a/docs/user_guide.md b/docs/user_guide.md index dde1f0e931..3c2e8f7edc 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -58,8 +58,11 @@ [A Faster KeepRunning Loop](#a-faster-keep-running-loop) +## Benchmarking Tips + [Disabling CPU Frequency Scaling](#disabling-cpu-frequency-scaling) +[Reducing Variance in Benchmarks](reducing_variance.md) @@ -1243,35 +1246,7 @@ If you see this error: ``` you might want to disable the CPU frequency scaling while running the -benchmark. Exactly how to do this depends on the Linux distribution, -desktop environment, and installed programs. Specific details are a moving -target, so we will not attempt to exhaustively document them here. - -One simple option is to use the `cpupower` program to change the -performance governor to "performance". This tool is maintained along with -the Linux kernel and provided by your distribution. - -It must be run as root, like this: - -```bash -sudo cpupower frequency-set --governor performance -``` - -After this you can verify that all CPUs are using the performance governor -by running this command: - -```bash -cpupower frequency-info -o proc -``` - -The benchmarks you subsequently run will have less variance. - -Note that changing the governor in this way will not persist across -reboots. To set the governor back, run the first command again with the -governor your system usually runs with, which varies. +benchmark, as well as consider other ways to stabilize the performance of +your system while benchmarking. -If you find yourself doing this often, there are probably better options -than running the commands above. Some approaches allow you to do this -without root access, or by using a GUI, etc. The Arch Wiki [Cpu frequency -scaling](https://wiki.archlinux.org/title/CPU_frequency_scaling) page is a -good place to start looking for options. +See [Reducing Variance](reducing_variance.md) for more information. From 926551125708ebe434cd765bfd1bc8ad51f1bd9a Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 13 Sep 2022 16:01:46 +0200 Subject: [PATCH 035/561] Bump pybind11 version to enable Python 3.11 wheel builds (#1489) This commit bumps the pybind11 version to 2.10.0, which is the first pybind version coming with Python 3.11 support. This change is necessary to facilitate wheel builds for Python 3.11 and upward, as changes to Python internals in 3.11 broke compatibility with older pybind11 versions. Co-authored-by: Dominic Hamon --- .github/workflows/wheels.yml | 2 +- WORKSPACE | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index aeea3b15e5..e8c8074018 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -48,7 +48,7 @@ jobs: - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@v2.9.0 env: - CIBW_BUILD: 'cp37-* cp38-* cp39-* cp310-*' + CIBW_BUILD: 'cp37-* cp38-* cp39-* cp310-* cp311-*' CIBW_SKIP: "cp37-*-arm64 *-musllinux_*" # TODO: Build ppc64le using some other trick CIBW_ARCHS_LINUX: x86_64 aarch64 diff --git a/WORKSPACE b/WORKSPACE index 949eb98bc5..6d1c51a0a6 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -19,9 +19,9 @@ git_repository( http_archive( name = "pybind11", build_file = "@//bindings/python:pybind11.BUILD", - sha256 = "1eed57bc6863190e35637290f97a20c81cfe4d9090ac0a24f3bbf08f265eb71d", - strip_prefix = "pybind11-2.4.3", - urls = ["https://github.com/pybind/pybind11/archive/v2.4.3.tar.gz"], + sha256 = "eacf582fa8f696227988d08cfc46121770823839fe9e301a20fbce67e7cd70ec", + strip_prefix = "pybind11-2.10.0", + urls = ["https://github.com/pybind/pybind11/archive/v2.10.0.tar.gz"], ) new_local_repository( From 49aa374da96199d64fd3de9673b6f405bbc3de3e Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 14 Sep 2022 15:11:37 +0100 Subject: [PATCH 036/561] bump cmake dep and docs (#1468) * bump cmake dep and docs --- .../workflows/build-and-test-perfcounters.yml | 49 +----- .github/workflows/build-and-test.yml | 160 ++---------------- .github/workflows/doxygen.yml | 8 +- .github/workflows/pylint.yml | 2 + CMakeLists.txt | 20 ++- docs/dependencies.md | 14 +- src/CMakeLists.txt | 1 - 7 files changed, 43 insertions(+), 211 deletions(-) diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index bb5a43f375..e162edcbef 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -14,7 +14,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, ubuntu-20.04] + # ubuntu-18.04 is deprecated but included for best-effort + os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04] build_type: ['Release', 'Debug'] steps: - uses: actions/checkout@v2 @@ -23,9 +24,10 @@ jobs: run: sudo apt -y install libpfm4-dev - name: setup cmake + if: matrix.os == 'ubuntu-18.04' uses: jwlawson/actions-setup-cmake@v1.9 with: - cmake-version: '3.5.1' + cmake-version: '3.16.3' - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build @@ -52,46 +54,3 @@ jobs: # working-directory: ${{ runner.workspace }}/_build # run: ctest -C ${{ matrix.build_type }} --rerun-failed --output-on-failure - ubuntu-16_04: - name: ubuntu-16.04.${{ matrix.build_type }} - runs-on: [ubuntu-latest] - strategy: - fail-fast: false - matrix: - build_type: ['Release', 'Debug'] - container: ubuntu:16.04 - steps: - - uses: actions/checkout@v2 - - - name: install required bits - run: | - apt update - apt -y install clang cmake g++ git - - - name: install libpfm - run: apt -y install libpfm4-dev - - - name: create build environment - run: cmake -E make_directory $GITHUB_WORKSPACE/_build - - - name: configure cmake - shell: bash - working-directory: ${{ github.workspace }}/_build - run: > - cmake $GITHUB_WORKSPACE - -DBENCHMARK_ENABLE_LIBPFM=1 - -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - - - name: build - shell: bash - working-directory: ${{ github.workspace }}/_build - run: cmake --build . --config ${{ matrix.build_type }} - - # Skip testing, for now. It seems perf_event_open does not succeed on the - # hosting machine, very likely a permissions issue. - # TODO(mtrofin): Enable test. - # - name: test - # shell: bash - # working-directory: ${{ runner.workspace }}/_build - # run: ctest -C ${{ matrix.build_type }} --rerun-failed --output-on-failure diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d7406a7332..2441e26b60 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,8 +1,10 @@ name: build-and-test on: - push: {} - pull_request: {} + push: + branches: [ main ] + pull_request: + branches: [ main ] jobs: # TODO: add 32-bit builds (g++ and clang++) for ubuntu @@ -15,7 +17,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, ubuntu-20.04, macos-latest] + # ubuntu-18.04 is deprecated but included for best-effort support + os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04, macos-latest] build_type: ['Release', 'Debug'] compiler: [g++, clang++] lib: ['shared', 'static'] @@ -23,21 +26,18 @@ jobs: steps: - uses: actions/checkout@v2 + - name: setup cmake + if: matrix.os == 'ubuntu-18.04' + uses: jwlawson/actions-setup-cmake@v1.9 + with: + cmake-version: '3.16.3' + - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build - name: setup cmake initial cache run: touch compiler-cache.cmake - - name: setup lto - # Workaround for enabling -flto on old GCC versions - if: matrix.build_type == 'Release' && startsWith(matrix.compiler, 'g++') && matrix.os != 'macos-latest' - run: > - echo 'set (CMAKE_CXX_FLAGS -flto CACHE STRING "")' >> compiler-cache.cmake; - echo 'set (CMAKE_RANLIB /usr/bin/gcc-ranlib CACHE FILEPATH "")' >> compiler-cache.cmake; - echo 'set (CMAKE_AR /usr/bin/gcc-ar CACHE FILEPATH "")' >> compiler-cache.cmake; - echo 'set (CMAKE_NM /usr/bin/gcc-nm CACHE FILEPATH "")' >> compiler-cache.cmake; - - name: configure cmake env: CXX: ${{ matrix.compiler }} @@ -113,140 +113,4 @@ jobs: - name: test run: ctest --test-dir _build/ -C ${{ matrix.build_type }} -VV - ubuntu-16_04: - name: ubuntu-16.04.${{ matrix.build_type }}.${{ matrix.compiler }} - runs-on: [ubuntu-latest] - strategy: - fail-fast: false - matrix: - build_type: ['Release', 'Debug'] - compiler: [g++, clang++] - container: ubuntu:16.04 - steps: - - uses: actions/checkout@v2 - - - name: install required bits - run: | - apt update - apt -y install clang cmake g++ git - - - name: create build environment - run: cmake -E make_directory $GITHUB_WORKSPACE/_build - - - name: setup cmake initial cache - run: touch compiler-cache.cmake - - - name: setup lto - # Workaround for enabling -flto on old GCC versions - # -Wl,--no-as-needed is needed to avoid the following linker error: - # - # /usr/lib/gcc/x86_64-linux-gnu/5/libstdc++.so: undefined reference to `pthread_create' - # - if: matrix.build_type == 'Release' && startsWith(matrix.compiler, 'g++') - run: > - echo 'set (CMAKE_CXX_FLAGS "-Wl,--no-as-needed -flto" CACHE STRING "")' >> compiler-cache.cmake; - echo 'set (CMAKE_RANLIB "/usr/bin/gcc-ranlib" CACHE FILEPATH "")' >> compiler-cache.cmake; - echo 'set (CMAKE_AR "/usr/bin/gcc-ar" CACHE FILEPATH "")' >> compiler-cache.cmake; - echo 'set (CMAKE_NM "/usr/bin/gcc-nm" CACHE FILEPATH "")' >> compiler-cache.cmake; - - - name: configure cmake - env: - CXX: ${{ matrix.compiler }} - shell: bash - working-directory: ${{ github.workspace }}/_build - run: > - cmake -C ../compiler-cache.cmake .. - -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON - -DBUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - -DCMAKE_CXX_VISIBILITY_PRESET=hidden - -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON - - - name: build - shell: bash - working-directory: ${{ github.workspace }}/_build - run: cmake --build . --config ${{ matrix.build_type }} - - name: test - shell: bash - working-directory: ${{ github.workspace }}/_build - run: ctest -C ${{ matrix.build_type }} -VV - - ubuntu-14_04: - name: ubuntu-14.04.${{ matrix.build_type }}.${{ matrix.compiler }} - runs-on: [ubuntu-latest] - strategy: - fail-fast: false - matrix: - build_type: ['Release', 'Debug'] - compiler: [g++-4.8, clang++-3.6] - include: - - compiler: g++-6 - build_type: 'Debug' - run_tests: true - - compiler: g++-6 - build_type: 'Release' - run_tests: true - container: ubuntu:14.04 - steps: - - uses: actions/checkout@v2 - - - name: install required bits - run: | - sudo apt update - sudo apt -y install clang-3.6 cmake3 g++-4.8 git - - - name: install other bits - if: ${{ matrix.compiler }} == g++-6 - run: | - sudo apt -y install software-properties-common - sudo add-apt-repository -y "ppa:ubuntu-toolchain-r/test" - sudo apt update - sudo apt -y install g++-6 - - - name: create build environment - run: cmake -E make_directory $GITHUB_WORKSPACE/_build - - - name: setup cmake initial cache - run: touch compiler-cache.cmake - - - name: setup lto - # Workaround for enabling -flto on old GCC versions - # -Wl,--no-as-needed is needed to avoid the following linker error: - # - # /usr/lib/gcc/x86_64-linux-gnu/6/libstdc++.so: undefined reference to `pthread_create' - # - if: matrix.build_type == 'Release' && startsWith(matrix.compiler, 'g++') - run: > - COMPILER=${{ matrix.compiler }}; - VERSION=${COMPILER#g++-}; - PREFIX=/usr/bin/gcc; - echo "set (CMAKE_CXX_FLAGS \"-Wl,--no-as-needed -flto\" CACHE STRING \"\")" >> compiler-cache.cmake; - echo "set (CMAKE_RANLIB \"$PREFIX-ranlib-$VERSION\" CACHE FILEPATH \"\")" >> compiler-cache.cmake; - echo "set (CMAKE_AR \"$PREFIX-ar-$VERSION\" CACHE FILEPATH \"\")" >> compiler-cache.cmake; - echo "set (CMAKE_NM \"$PREFIX-nm-$VERSION\" CACHE FILEPAT \"\")" >> compiler-cache.cmake; - - - name: configure cmake - env: - CXX: ${{ matrix.compiler }} - shell: bash - working-directory: ${{ github.workspace }}/_build - run: > - cmake -C ../compiler-cache.cmake .. - -DBENCHMARK_DOWNLOAD_DEPENDENCIES=${{ matrix.run_tests }} - -DBENCHMARK_ENABLE_TESTING=${{ matrix.run_tests }} - -DBUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - -DCMAKE_CXX_VISIBILITY_PRESET=hidden - -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON - - - name: build - shell: bash - working-directory: ${{ github.workspace }}/_build - run: cmake --build . --config ${{ matrix.build_type }} - - - name: test - if: ${{ matrix.run_tests }} - shell: bash - working-directory: ${{ github.workspace }}/_build - run: ctest -C ${{ matrix.build_type }} -VV diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index dc55011b8b..e15e69e3ca 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -13,13 +13,15 @@ jobs: steps: - name: Fetching sources uses: actions/checkout@v2 + - name: Installing build dependencies run: | sudo apt update - sudo apt install cmake doxygen gcc git + sudo apt install doxygen gcc git + - name: Creating build directory - run: | - mkdir build + run: mkdir build + - name: Building HTML documentation with Doxygen run: | cmake -S . -B build -DBENCHMARK_ENABLE_TESTING:BOOL=OFF -DBENCHMARK_ENABLE_DOXYGEN:BOOL=ON -DBENCHMARK_INSTALL_DOCS:BOOL=ON diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 0f73a58232..f6d368b48e 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -17,10 +17,12 @@ jobs: uses: actions/setup-python@v1 with: python-version: 3.8 + - name: Install dependencies run: | python -m pip install --upgrade pip pip install pylint pylint-exit conan + - name: Run pylint run: | pylint `find . -name '*.py'|xargs` || pylint-exit $? diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d636bea75..ae1f2ef1c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.5.1) +cmake_minimum_required (VERSION 3.16.3) foreach(p CMP0048 # OK to clear PROJECT_VERSION on project() @@ -6,6 +6,7 @@ foreach(p CMP0056 # export EXE_LINKER_FLAGS to try_run CMP0057 # Support no if() IN_LIST operator CMP0063 # Honor visibility properties for all targets + CMP0067 # Honor language standard in try_compile() source file signature CMP0077 # Allow option() overrides in importing projects ) if(POLICY ${p}) @@ -137,6 +138,16 @@ if (BENCHMARK_BUILD_32_BITS) add_required_cxx_compiler_flag(-m32) endif() +if (MSVC) + set(BENCHMARK_CXX_STANDARD 14) +else() + set(BENCHMARK_CXX_STANDARD 11) +endif() + +set(CMAKE_CXX_STANDARD ${BENCHMARK_CXX_STANDARD}) +set(CMAKE_CXX_STANDARD_REQUIRED YES) +set(CMAKE_CXX_EXTENSIONS OFF) + if (MSVC) # Turn compiler warnings up to 11 string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") @@ -169,13 +180,6 @@ if (MSVC) set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG") endif() else() - # Try and enable C++11. Don't use C++14 because it doesn't work in some - # configurations. - add_cxx_compiler_flag(-std=c++11) - if (NOT HAVE_CXX_FLAG_STD_CXX11) - add_cxx_compiler_flag(-std=c++0x) - endif() - # Turn compiler warnings up to 11 add_cxx_compiler_flag(-Wall) add_cxx_compiler_flag(-Wextra) diff --git a/docs/dependencies.md b/docs/dependencies.md index 7af52b95bd..57003aa334 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -7,13 +7,15 @@ still allow forward progress, we require any build tooling to be available for: * The last two Ubuntu LTS releases Currently, this means using build tool versions that are available for Ubuntu -18.04 (Bionic Beaver), Ubuntu 20.04 (Focal Fossa), and Debian 11 (bullseye). +Ubuntu 20.04 (Focal Fossa), Ubuntu 22.04 (Jammy Jellyfish) and Debian 11.4 (bullseye). -_Note, CI also runs ubuntu-16.04 and ubuntu-14.04 to ensure best effort support -for older versions._ +_Note, CI also runs ubuntu-18.04 to attempt best effort support for older versions._ ## cmake -The current supported version is cmake 3.5.1 as of 2018-06-06. +The current supported version is cmake 3.16.3 as of 2022-08-10. + +* _3.10.2 (ubuntu 18.04)_ +* 3.16.3 (ubuntu 20.04) +* 3.18.4 (debian 11.4) +* 3.22.1 (ubuntu 22.04) -_Note, this version is also available for Ubuntu 14.04, an older Ubuntu LTS -release, as `cmake3`._ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 55402e6585..7f2c88b5ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,7 +69,6 @@ set_target_properties(benchmark_main PROPERTIES ) target_link_libraries(benchmark_main PUBLIC benchmark::benchmark) - set(generated_dir "${PROJECT_BINARY_DIR}") set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") From d2a8a4ee41b923876c034afb939c4fc03598e622 Mon Sep 17 00:00:00 2001 From: Marat Dukhan Date: Tue, 4 Oct 2022 12:43:27 -0700 Subject: [PATCH 037/561] Support for QuRT OS (Hexagon RTOS) (#1497) --- include/benchmark/benchmark.h | 7 +++++++ src/benchmark.cc | 2 +- src/benchmark_register.cc | 2 +- src/benchmark_runner.cc | 2 +- src/cycleclock.h | 4 ++++ src/internal_macros.h | 2 ++ src/reporter.cc | 4 ++++ src/sysinfo.cc | 26 ++++++++++++++++++++++++-- src/timers.cc | 15 +++++++++++++-- 9 files changed, 57 insertions(+), 7 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index bc426ca3e1..fefe9b20e5 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1534,8 +1534,15 @@ class Fixture : public internal::Benchmark { #endif // Helper macro to create a main routine in a test that runs the benchmarks +// Note the workaround for Hexagon simulator passing argc != 0, argv = NULL. #define BENCHMARK_MAIN() \ int main(int argc, char** argv) { \ + char arg0_default[] = "benchmark"; \ + char* args_default = arg0_default; \ + if (!argv) { \ + argc = 1; \ + argv = &args_default; \ + } \ ::benchmark::Initialize(&argc, argv); \ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; \ ::benchmark::RunSpecifiedBenchmarks(); \ diff --git a/src/benchmark.cc b/src/benchmark.cc index f18c30810f..ff2864804c 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -19,7 +19,7 @@ #include "internal_macros.h" #ifndef BENCHMARK_OS_WINDOWS -#ifndef BENCHMARK_OS_FUCHSIA +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) #include #endif #include diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index a42b76689b..eae2c320f6 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -15,7 +15,7 @@ #include "benchmark_register.h" #ifndef BENCHMARK_OS_WINDOWS -#ifndef BENCHMARK_OS_FUCHSIA +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) #include #endif #include diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 0fb74bfac8..fd6da53ffd 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -19,7 +19,7 @@ #include "internal_macros.h" #ifndef BENCHMARK_OS_WINDOWS -#ifndef BENCHMARK_OS_FUCHSIA +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) #include #endif #include diff --git a/src/cycleclock.h b/src/cycleclock.h index 04f094feaa..df6ffa51ae 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -212,6 +212,10 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { struct timeval tv; gettimeofday(&tv, nullptr); return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#elif defined(__hexagon__) + uint64_t pcycle; + asm volatile("%0 = C15:14" : "=r"(pcycle)); + return static_cast(pcycle); #else // The soft failover to a generic implementation is automatic only for ARM. // For other platforms the developer is expected to make an attempt to create diff --git a/src/internal_macros.h b/src/internal_macros.h index 1fe1eb6a23..396a390afb 100644 --- a/src/internal_macros.h +++ b/src/internal_macros.h @@ -85,6 +85,8 @@ #define BENCHMARK_OS_QNX 1 #elif defined(__MVS__) #define BENCHMARK_OS_ZOS 1 +#elif defined(__hexagon__) +#define BENCHMARK_OS_QURT 1 #endif #if defined(__ANDROID__) && defined(__GLIBCXX__) diff --git a/src/reporter.cc b/src/reporter.cc index 8b5fdaff65..076bc31a2e 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -36,7 +36,11 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, BM_CHECK(out) << "cannot be null"; auto &Out = *out; +#ifndef BENCHMARK_OS_QURT + // Date/time information is not available on QuRT. + // Attempting to get it via this call cause the binary to crash. Out << LocalDateTimeString() << "\n"; +#endif if (context.executable_name) Out << "Running " << context.executable_name << "\n"; diff --git a/src/sysinfo.cc b/src/sysinfo.cc index b91739b1e3..41f2d36e0a 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -23,7 +23,7 @@ #include #else #include -#ifndef BENCHMARK_OS_FUCHSIA +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) #include #endif #include @@ -42,6 +42,9 @@ #if defined(BENCHMARK_OS_QNX) #include #endif +#if defined(BENCHMARK_OS_QURT) +#include +#endif #include #include @@ -402,6 +405,8 @@ std::vector GetCacheSizes() { return GetCacheSizesWindows(); #elif defined(BENCHMARK_OS_QNX) return GetCacheSizesQNX(); +#elif defined(BENCHMARK_OS_QURT) + return std::vector(); #else return GetCacheSizesFromKVFS(); #endif @@ -432,7 +437,15 @@ std::string GetSystemName() { str = std::string(converted.data()); #endif return str; -#else // defined(BENCHMARK_OS_WINDOWS) +#elif defined(BENCHMARK_OS_QURT) + std::string str = "Hexagon DSP"; + qurt_arch_version_t arch_version_struct; + if (qurt_sysenv_get_arch_version(&arch_version_struct) == QURT_EOK) { + str += " v"; + str += std::to_string(arch_version_struct.arch_version); + } + return str; +#else #ifndef HOST_NAME_MAX #ifdef BENCHMARK_HAS_SYSCTL // BSD/Mac Doesnt have HOST_NAME_MAX defined #define HOST_NAME_MAX 64 @@ -479,6 +492,12 @@ int GetNumCPUs() { return num_cpu; #elif defined(BENCHMARK_OS_QNX) return static_cast(_syspage_ptr->num_cpu); +#elif defined(BENCHMARK_OS_QURT) + qurt_sysenv_max_hthreads_t hardware_threads; + if (qurt_sysenv_get_max_hw_threads(&hardware_threads) != QURT_EOK) { + hardware_threads.max_hthreads = 1; + } + return hardware_threads.max_hthreads; #else int num_cpus = 0; int max_id = -1; @@ -678,6 +697,9 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { #elif defined(BENCHMARK_OS_QNX) return static_cast((int64_t)(SYSPAGE_ENTRY(cpuinfo)->speed) * (int64_t)(1000 * 1000)); +#elif defined(BENCHMARK_OS_QURT) + // QuRT doesn't provide any API to query Hexagon frequency. + return 1000000000; #endif // If we've fallen through, attempt to roughly estimate the CPU clock rate. static constexpr int estimate_time_ms = 1000; diff --git a/src/timers.cc b/src/timers.cc index 68612e2688..379d97dd22 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -23,7 +23,7 @@ #include #else #include -#ifndef BENCHMARK_OS_FUCHSIA +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) #include #endif #include @@ -38,6 +38,9 @@ #include #include #endif +#if defined(BENCHMARK_OS_QURT) +#include +#endif #endif #ifdef BENCHMARK_OS_EMSCRIPTEN @@ -79,7 +82,7 @@ double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) { static_cast(user.QuadPart)) * 1e-7; } -#elif !defined(BENCHMARK_OS_FUCHSIA) +#elif !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) double MakeTime(struct rusage const& ru) { return (static_cast(ru.ru_utime.tv_sec) + static_cast(ru.ru_utime.tv_usec) * 1e-6 + @@ -119,6 +122,10 @@ double ProcessCPUUsage() { &user_time)) return MakeTime(kernel_time, user_time); DiagnoseAndExit("GetProccessTimes() failed"); +#elif defined(BENCHMARK_OS_QURT) + return static_cast( + qurt_timer_timetick_to_us(qurt_timer_get_ticks())) * + 1.0e-6; #elif defined(BENCHMARK_OS_EMSCRIPTEN) // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten. // Use Emscripten-specific API. Reported CPU time would be exactly the @@ -149,6 +156,10 @@ double ThreadCPUUsage() { GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time, &user_time); return MakeTime(kernel_time, user_time); +#elif defined(BENCHMARK_OS_QURT) + return static_cast( + qurt_timer_timetick_to_us(qurt_timer_get_ticks())) * + 1.0e-6; #elif defined(BENCHMARK_OS_MACOSX) // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. // See https://github.com/google/benchmark/pull/292 From 12e0d70a436f01951f857f6b2fc63c8c92a1884e Mon Sep 17 00:00:00 2001 From: rorth Date: Thu, 6 Oct 2022 10:18:55 +0200 Subject: [PATCH 038/561] Fix Solaris compilation (#1499) (#1500) This patch fixes compilation on Solaris, addressing the problems reported in Issue #1499: * Provide `HOST_NAME_MAX` definition. * Match `sysconf(3C)` return type. * Avoid `-Wcast-qual` warnings with `libkstat(3KSTAT)` functions. * Avoid clash with `` `single` typedef. --- AUTHORS | 1 + CONTRIBUTORS | 1 + src/sysinfo.cc | 14 +++++++++----- test/benchmark_setup_teardown_test.cc | 12 ++++++------ 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7d689350b5..3f3fd37037 100644 --- a/AUTHORS +++ b/AUTHORS @@ -51,6 +51,7 @@ Oleksandr Sochka Ori Livneh Paul Redmond Radoslav Yovchev +Rainer Orth Roman Lebedev Sayan Bhattacharjee Shapr3D diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4208e0cf51..6fe918ebe5 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -73,6 +73,7 @@ Pascal Leroy Paul Redmond Pierre Phaneuf Radoslav Yovchev +Rainer Orth Raul Marin Ray Glover Robert Guo diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 41f2d36e0a..917429ad37 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -38,6 +38,7 @@ #endif #if defined(BENCHMARK_OS_SOLARIS) #include +#include #endif #if defined(BENCHMARK_OS_QNX) #include @@ -455,6 +456,8 @@ std::string GetSystemName() { #define HOST_NAME_MAX 154 #elif defined(BENCHMARK_OS_RTEMS) #define HOST_NAME_MAX 256 +#elif defined(BENCHMARK_OS_SOLARIS) +#define HOST_NAME_MAX MAXHOSTNAMELEN #else #pragma message("HOST_NAME_MAX not defined. using 64") #define HOST_NAME_MAX 64 @@ -484,12 +487,12 @@ int GetNumCPUs() { // group #elif defined(BENCHMARK_OS_SOLARIS) // Returns -1 in case of a failure. - int num_cpu = sysconf(_SC_NPROCESSORS_ONLN); + long num_cpu = sysconf(_SC_NPROCESSORS_ONLN); if (num_cpu < 0) { fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n", strerror(errno)); } - return num_cpu; + return (int)num_cpu; #elif defined(BENCHMARK_OS_QNX) return static_cast(_syspage_ptr->num_cpu); #elif defined(BENCHMARK_OS_QURT) @@ -671,7 +674,8 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { std::cerr << "failed to open /dev/kstat\n"; return -1; } - kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, (char*)"cpu_info0"); + kstat_t* ksp = kstat_lookup(kc, const_cast("cpu_info"), -1, + const_cast("cpu_info0")); if (!ksp) { std::cerr << "failed to lookup in /dev/kstat\n"; return -1; @@ -680,8 +684,8 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { std::cerr << "failed to read from /dev/kstat\n"; return -1; } - kstat_named_t* knp = - (kstat_named_t*)kstat_data_lookup(ksp, (char*)"current_clock_Hz"); + kstat_named_t* knp = (kstat_named_t*)kstat_data_lookup( + ksp, const_cast("current_clock_Hz")); if (!knp) { std::cerr << "failed to lookup data in /dev/kstat\n"; return -1; diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index efa34e15c1..f67175953a 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -10,19 +10,19 @@ // Test that Setup() and Teardown() are called exactly once // for each benchmark run (single-threaded). -namespace single { +namespace singlethreaded { static int setup_call = 0; static int teardown_call = 0; -} // namespace single +} // namespace singlethreaded static void DoSetup1(const benchmark::State& state) { - ++single::setup_call; + ++singlethreaded::setup_call; // Setup/Teardown should never be called with any thread_idx != 0. assert(state.thread_index() == 0); } static void DoTeardown1(const benchmark::State& state) { - ++single::teardown_call; + ++singlethreaded::teardown_call; assert(state.thread_index() == 0); } @@ -134,8 +134,8 @@ int main(int argc, char** argv) { assert(ret > 0); // Setup/Teardown is called once for each arg group (1,3,5,7). - assert(single::setup_call == 4); - assert(single::teardown_call == 4); + assert(singlethreaded::setup_call == 4); + assert(singlethreaded::teardown_call == 4); // 3 group of threads calling this function (3,5,10). assert(concurrent::setup_call.load(std::memory_order_relaxed) == 3); From 229bc5a93729d72b97a77759b2ba991008c4e330 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Mon, 10 Oct 2022 04:46:41 -0700 Subject: [PATCH 039/561] Do not depend on unversioned python binary (#1496) Some linux distributions no longer provide `python` binary and require usage of `python3` instead. This changes the scripts here and uses cmake `find_package(Python3` when running python. Co-authored-by: Dominic Hamon --- CMakeLists.txt | 1 + test/AssemblyTests.cmake | 2 +- tools/compare.py | 2 +- tools/strip_asm.py | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae1f2ef1c1..22b5306ba5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -332,6 +332,7 @@ include_directories(${PROJECT_SOURCE_DIR}/include) add_subdirectory(src) if (BENCHMARK_ENABLE_TESTING) + find_package(Python3 3.6 REQUIRED COMPONENTS Interpreter) enable_testing() if (BENCHMARK_ENABLE_GTEST_TESTS AND NOT (TARGET gtest AND TARGET gtest_main AND diff --git a/test/AssemblyTests.cmake b/test/AssemblyTests.cmake index c43c711faf..9ebe948eaa 100644 --- a/test/AssemblyTests.cmake +++ b/test/AssemblyTests.cmake @@ -47,7 +47,7 @@ macro(add_filecheck_test name) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "-S ${ASM_TEST_FLAGS}") set(ASM_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${name}.s") add_custom_target(copy_${name} ALL - COMMAND ${PROJECT_SOURCE_DIR}/tools/strip_asm.py + COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/strip_asm.py $ ${ASM_OUTPUT_FILE} BYPRODUCTS ${ASM_OUTPUT_FILE}) diff --git a/tools/compare.py b/tools/compare.py index 01d2c89f50..8cefdd17c1 100755 --- a/tools/compare.py +++ b/tools/compare.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import unittest """ diff --git a/tools/strip_asm.py b/tools/strip_asm.py index 9030550b43..d131dc7194 100755 --- a/tools/strip_asm.py +++ b/tools/strip_asm.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ strip_asm.py - Cleanup ASM output for the specified file From db4f581fbbff2fddeef0a01983f3e62c758137a3 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 13 Oct 2022 12:03:29 +0300 Subject: [PATCH 040/561] Partially revert "Do not depend on unversioned python binary (#1496)" (#1501) As predicted, the cmake part of the change is contentious. https://github.com/google/benchmark/pull/1496#issuecomment-1276508266 This partially reverts commit 229bc5a93729d72b97a77759b2ba991008c4e330. --- CMakeLists.txt | 1 - test/AssemblyTests.cmake | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22b5306ba5..ae1f2ef1c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -332,7 +332,6 @@ include_directories(${PROJECT_SOURCE_DIR}/include) add_subdirectory(src) if (BENCHMARK_ENABLE_TESTING) - find_package(Python3 3.6 REQUIRED COMPONENTS Interpreter) enable_testing() if (BENCHMARK_ENABLE_GTEST_TESTS AND NOT (TARGET gtest AND TARGET gtest_main AND diff --git a/test/AssemblyTests.cmake b/test/AssemblyTests.cmake index 9ebe948eaa..c43c711faf 100644 --- a/test/AssemblyTests.cmake +++ b/test/AssemblyTests.cmake @@ -47,7 +47,7 @@ macro(add_filecheck_test name) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "-S ${ASM_TEST_FLAGS}") set(ASM_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${name}.s") add_custom_target(copy_${name} ALL - COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/strip_asm.py + COMMAND ${PROJECT_SOURCE_DIR}/tools/strip_asm.py $ ${ASM_OUTPUT_FILE} BYPRODUCTS ${ASM_OUTPUT_FILE}) From 4eaa0c896db50451e7cb38c9bcd9cde21713852e Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 18 Oct 2022 12:23:59 +0200 Subject: [PATCH 041/561] Add information for supported Python versions to setup.py (#1502) Adds qualifiers for Python 3.9-3.11 indicating them being supported in the Python bindings building. Support for Python 3.6 was removed, so the indicator for Python 3.6 was removed. --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 78801b4219..e9d598a0f9 100644 --- a/setup.py +++ b/setup.py @@ -147,9 +147,11 @@ def bazel_build(self, ext): "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Software Development :: Testing", "Topic :: System :: Benchmark", ], From 398a8ac2e8e0b852fa1568dc1c8ebdfc743a380a Mon Sep 17 00:00:00 2001 From: Raghu Raja Date: Mon, 31 Oct 2022 04:03:59 -0700 Subject: [PATCH 042/561] [bazel] Build libpfm as a dependency to allow collection of perf counters (#1408) * Build libpfm as a dependency to allow collection of perf counters This commit builds libpfm using rules_foreign_cc and lets the default build of the benchmark library support perf counter collection without needing additional work from users. Tested with a custom target: ``` bazel run \ --override_repository=com_github_google_benchmark=/home/raghu/benchmark \ -c opt :test-bench -- "--benchmark_perf_counters=INSTRUCTIONS,CYCLES" Using profile: local ---------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... ---------------------------------------------------------------------- BM_Test 0.279 ns 0.279 ns 1000000000 CYCLES=1.00888 INSTRUCTIONS=2 ``` Signed-off-by: Raghu Raja * Adding myself to the CONTRIBUTORS file per CLA guidance Enfabrica has already signed a corporate CLA. Signed-off-by: Raghu Raja Signed-off-by: Raghu Raja --- AUTHORS | 1 + BUILD.bazel | 19 ++++++++++++++++++- CONTRIBUTORS | 1 + WORKSPACE | 31 +++++++++++++++++++++++++++++++ docs/perf_counters.md | 13 +++++++------ tools/libpfm.BUILD.bazel | 21 +++++++++++++++++++++ 6 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 tools/libpfm.BUILD.bazel diff --git a/AUTHORS b/AUTHORS index 3f3fd37037..98d2d98b05 100644 --- a/AUTHORS +++ b/AUTHORS @@ -50,6 +50,7 @@ Norman Heino Oleksandr Sochka Ori Livneh Paul Redmond +Raghu Raja Radoslav Yovchev Rainer Orth Roman Lebedev diff --git a/BUILD.bazel b/BUILD.bazel index af18e3d7de..64f86eedc9 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -18,6 +18,14 @@ config_setting( visibility = [":__subpackages__"], ) +config_setting( + name = "perfcounters", + define_values = { + "pfm": "1", + }, + visibility = [":__subpackages__"], +) + cc_library( name = "benchmark", srcs = glob( @@ -41,7 +49,16 @@ cc_library( # Using `defines` (i.e. not `local_defines`) means that no # dependent rules need to bother about defining the macro. linkstatic = True, - defines = ["BENCHMARK_STATIC_DEFINE"], + defines = [ + "BENCHMARK_STATIC_DEFINE", + ] + select({ + ":perfcounters": ["HAVE_LIBPFM"], + "//conditions:default": [], + }), + deps = select({ + ":perfcounters": ["@libpfm//:libpfm"], + "//conditions:default": [], + }), ) cc_library( diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 6fe918ebe5..32ab15bbe0 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -74,6 +74,7 @@ Paul Redmond Pierre Phaneuf Radoslav Yovchev Rainer Orth +Raghu Raja Raul Marin Ray Glover Robert Guo diff --git a/WORKSPACE b/WORKSPACE index 6d1c51a0a6..b468abafd5 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -3,6 +3,27 @@ workspace(name = "com_github_google_benchmark") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +http_archive( + name = "bazel_skylib", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + ], + sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", +) + +# https://github.com/bazelbuild/rules_foreign_cc/ +http_archive( + name = "rules_foreign_cc", + sha256 = "bcd0c5f46a49b85b384906daae41d277b3dc0ff27c7c752cc51e43048a58ec83", + strip_prefix = "rules_foreign_cc-0.7.1", + url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.7.1.tar.gz", +) + +load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") +rules_foreign_cc_dependencies() + http_archive( name = "com_google_absl", sha256 = "f41868f7a938605c92936230081175d1eae87f6ea2c248f41077c8f88316f111", @@ -16,6 +37,16 @@ git_repository( tag = "release-1.11.0", ) +# Downloaded from v4.9.0 tag at https://sourceforge.net/p/perfmon2/libpfm4/ref/master/tags/ +http_archive( + name = "libpfm", + build_file = "//tools:libpfm.BUILD.bazel", + sha256 = "5da5f8872bde14b3634c9688d980f68bda28b510268723cc12973eedbab9fecc", + type = "tar.gz", + strip_prefix = "libpfm-4.11.0", + urls = ["https://sourceforge.net/projects/perfmon2/files/libpfm4/libpfm-4.11.0.tar.gz/download"], +) + http_archive( name = "pybind11", build_file = "@//bindings/python:pybind11.BUILD", diff --git a/docs/perf_counters.md b/docs/perf_counters.md index 74560e9669..db83145c9a 100644 --- a/docs/perf_counters.md +++ b/docs/perf_counters.md @@ -12,16 +12,17 @@ This feature is available if: * The benchmark is run on an architecture featuring a Performance Monitoring Unit (PMU), * The benchmark is compiled with support for collecting counters. Currently, - this requires [libpfm](http://perfmon2.sourceforge.net/) be available at build - time + this requires [libpfm](http://perfmon2.sourceforge.net/), which is built as a + dependency via Bazel. The feature does not require modifying benchmark code. Counter collection is handled at the boundaries where timer collection is also handled. To opt-in: - -* Install `libpfm4-dev`, e.g. `apt-get install libpfm4-dev`. -* Enable the cmake flag BENCHMARK_ENABLE_LIBPFM. +* If using a Bazel build, add `--define pfm=1` to your buid flags +* If using CMake: + * Install `libpfm4-dev`, e.g. `apt-get install libpfm4-dev`. + * Enable the CMake flag `BENCHMARK_ENABLE_LIBPFM` in `CMakeLists.txt`. To use, pass a comma-separated list of counter names through the `--benchmark_perf_counters` flag. The names are decoded through libpfm - meaning, @@ -31,4 +32,4 @@ mapped by libpfm to platform-specifics - see libpfm The counter values are reported back through the [User Counters](../README.md#custom-counters) mechanism, meaning, they are available in all the formats (e.g. JSON) supported -by User Counters. \ No newline at end of file +by User Counters. diff --git a/tools/libpfm.BUILD.bazel b/tools/libpfm.BUILD.bazel new file mode 100644 index 0000000000..f661064fd5 --- /dev/null +++ b/tools/libpfm.BUILD.bazel @@ -0,0 +1,21 @@ +# Build rule for libpfm, which is required to collect performance counters for +# BENCHMARK_ENABLE_LIBPFM builds. + +load("@rules_foreign_cc//foreign_cc:defs.bzl", "make") + +filegroup( + name = "pfm_srcs", + srcs = glob(["**"]), +) + +make( + name = "libpfm", + lib_source = ":pfm_srcs", + lib_name = "libpfm", + copts = [ + "-Wno-format-truncation", + ], + visibility = [ + "//visibility:public", + ], +) From d572f4777349d43653b21d6c2fc63020ab326db2 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Fri, 11 Nov 2022 14:01:03 +0000 Subject: [PATCH 043/561] version bump for release --- CMakeLists.txt | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae1f2ef1c1..9ab265ed88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ foreach(p endif() endforeach() -project (benchmark VERSION 1.7.0 LANGUAGES CXX) +project (benchmark VERSION 1.7.1 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 3dfabfb344..10f5d5ddea 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -69,7 +69,7 @@ def my_benchmark(state): "State", ] -__version__ = "1.7.0" +__version__ = "1.7.1" class __OptionMaker: From 9714eb8d118ff75da1f887f41645f7c4fab3e58f Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Fri, 11 Nov 2022 10:12:12 -0500 Subject: [PATCH 044/561] Removed deprecated function (#1506) * Removed deprecated function * updated tests too * restore comment Co-authored-by: dominic hamon --- include/benchmark/benchmark.h | 8 +------- src/benchmark_runner.cc | 5 +---- test/memory_manager_test.cc | 6 +++--- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index fefe9b20e5..54d4e3cf0c 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -383,13 +383,7 @@ class MemoryManager { virtual void Start() = 0; // Implement this to stop recording and fill out the given Result structure. - BENCHMARK_DEPRECATED_MSG("Use Stop(Result&) instead") - virtual void Stop(Result* result) = 0; - - // FIXME(vyng): Make this pure virtual once we've migrated current users. - BENCHMARK_DISABLE_DEPRECATED_WARNING - virtual void Stop(Result& result) { Stop(&result); } - BENCHMARK_RESTORE_DEPRECATED_WARNING + virtual void Stop(Result& result) = 0; }; // Register a MemoryManager instance that will be used to collect and report diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index fd6da53ffd..04e5c2a758 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -387,10 +387,7 @@ void BenchmarkRunner::DoOneRepetition() { manager->WaitForAllThreads(); manager.reset(); b.Teardown(); - - BENCHMARK_DISABLE_DEPRECATED_WARNING - memory_manager->Stop(memory_result); - BENCHMARK_RESTORE_DEPRECATED_WARNING + memory_manager->Stop(*memory_result); } // Ok, now actually report. diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index f0c192fcbd..4b08f3f77b 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -6,9 +6,9 @@ class TestMemoryManager : public benchmark::MemoryManager { void Start() BENCHMARK_OVERRIDE {} - void Stop(Result* result) BENCHMARK_OVERRIDE { - result->num_allocs = 42; - result->max_bytes_used = 42000; + void Stop(Result& result) BENCHMARK_OVERRIDE { + result.num_allocs = 42; + result.max_bytes_used = 42000; } }; From 2257fa4d6afb8e5a2ccd510a70f38fe7fcdf1edf Mon Sep 17 00:00:00 2001 From: Maxim Smolskiy Date: Sat, 12 Nov 2022 03:50:16 +0300 Subject: [PATCH 045/561] Return option benchmark_perf_counters to help output (#1508) * Return option benchmark_perf_counters to help output * Add guard HAVE_LIBPFM --- src/benchmark.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/benchmark.cc b/src/benchmark.cc index ff2864804c..12b2d16d24 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -676,6 +676,9 @@ void PrintDefaultHelp() { " [--benchmark_out_format=]\n" " [--benchmark_color={auto|true|false}]\n" " [--benchmark_counters_tabular={true|false}]\n" +#if defined HAVE_LIBPFM + " [--benchmark_perf_counters=,...]\n" +#endif " [--benchmark_context==,...]\n" " [--benchmark_time_unit={ns|us|ms|s}]\n" " [--v=]\n"); From e67028c510196783b4cb8143d62f81f570fd828b Mon Sep 17 00:00:00 2001 From: Jessy De Lannoit Date: Tue, 6 Dec 2022 13:51:41 +0200 Subject: [PATCH 046/561] Fixes incorrect wide string conversion on win32 (#1516) * fixes incorrect wide string conversion on win32 * removed redundant error checks --- src/sysinfo.cc | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 917429ad37..41c0f9f954 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -423,19 +423,12 @@ std::string GetSystemName() { #ifndef UNICODE str = std::string(hostname, DWCOUNT); #else - std::vector converted; - // Find the length first. - int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname, - DWCOUNT, converted.begin(), 0); - // TODO: Report error from GetLastError()? - if (len == 0) return std::string(""); - converted.reserve(len + 1); - - len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname, DWCOUNT, - converted.begin(), converted.size()); - // TODO: Report error from GetLastError()? - if (len == 0) return std::string(""); - str = std::string(converted.data()); + // `WideCharToMultiByte` returns `0` when conversion fails. + int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, hostname, + DWCOUNT, NULL, 0, NULL, NULL); + str.resize(len); + WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, hostname, DWCOUNT, &str[0], + str.size(), NULL, NULL); #endif return str; #elif defined(BENCHMARK_OS_QURT) From da652a748675b679947710117329e9f77f374f2d Mon Sep 17 00:00:00 2001 From: dominic hamon <510002+dmah42@users.noreply.github.com> Date: Sat, 10 Dec 2022 19:42:44 -0400 Subject: [PATCH 047/561] Try removing attempt to set the C++ standard (#1464) * Try removing attempt to set the C++ standard Fixes #1460 #1462 * set the standard to 11 * spell it right * had it right the first time * require std 11 * plumb through the standard to cxxfeaturecheck * use policy instead * can't use policy just yet * Update CXXFeatureCheck.cmake * fix CXX_STANDARD_REQUIRED statement Co-authored-by: Dominic Hamon --- CMakeLists.txt | 4 ++++ cmake/CXXFeatureCheck.cmake | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ab265ed88..9b9dd38e89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,10 @@ if (BENCHMARK_BUILD_32_BITS) add_required_cxx_compiler_flag(-m32) endif() +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + if (MSVC) set(BENCHMARK_CXX_STANDARD 14) else() diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index 50e5f680b5..e51482659b 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -40,6 +40,8 @@ function(cxx_feature_check FILE) message(STATUS "Cross-compiling to test ${FEATURE}") try_compile(COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) @@ -54,6 +56,8 @@ function(cxx_feature_check FILE) message(STATUS "Compiling and running to test ${FEATURE}") try_run(RUN_${FEATURE} COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) From dfd2ae520a33819428bab7fe232ee4d4a7ca9821 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 19 Dec 2022 12:12:32 +0100 Subject: [PATCH 048/561] Add a `benchmark_deps.bzl` function to Google Benchmark (#1520) * Add `benchmark_workspace.bzl` function This commit adds a `benchmark_workspace.bzl` function to Google Benchmark. It is intended to be used as a means to pull in Google Benchmark's build dependencies in its own Bazel workspace, as well as in workspaces of downstream projects. * Migrate WORKSPACE to use the newly created benchmark_deps.bzl This commit changes Google Benchmark's own WORKSPACE to use the newly created `benchmark_deps.bzl` function. --- WORKSPACE | 67 +++++----------------------------------- bazel/benchmark_deps.bzl | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 60 deletions(-) create mode 100644 bazel/benchmark_deps.bzl diff --git a/WORKSPACE b/WORKSPACE index b468abafd5..6dab3d951d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,58 +1,18 @@ workspace(name = "com_github_google_benchmark") -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") +load("//:bazel/benchmark_deps.bzl", "benchmark_deps") - -http_archive( - name = "bazel_skylib", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", - ], - sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", -) - -# https://github.com/bazelbuild/rules_foreign_cc/ -http_archive( - name = "rules_foreign_cc", - sha256 = "bcd0c5f46a49b85b384906daae41d277b3dc0ff27c7c752cc51e43048a58ec83", - strip_prefix = "rules_foreign_cc-0.7.1", - url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.7.1.tar.gz", -) +benchmark_deps() load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") -rules_foreign_cc_dependencies() - -http_archive( - name = "com_google_absl", - sha256 = "f41868f7a938605c92936230081175d1eae87f6ea2c248f41077c8f88316f111", - strip_prefix = "abseil-cpp-20200225.2", - urls = ["https://github.com/abseil/abseil-cpp/archive/20200225.2.tar.gz"], -) -git_repository( - name = "com_google_googletest", - remote = "https://github.com/google/googletest.git", - tag = "release-1.11.0", -) +rules_foreign_cc_dependencies() -# Downloaded from v4.9.0 tag at https://sourceforge.net/p/perfmon2/libpfm4/ref/master/tags/ -http_archive( - name = "libpfm", - build_file = "//tools:libpfm.BUILD.bazel", - sha256 = "5da5f8872bde14b3634c9688d980f68bda28b510268723cc12973eedbab9fecc", - type = "tar.gz", - strip_prefix = "libpfm-4.11.0", - urls = ["https://sourceforge.net/projects/perfmon2/files/libpfm4/libpfm-4.11.0.tar.gz/download"], -) +load("@rules_python//python:pip.bzl", pip3_install="pip_install") -http_archive( - name = "pybind11", - build_file = "@//bindings/python:pybind11.BUILD", - sha256 = "eacf582fa8f696227988d08cfc46121770823839fe9e301a20fbce67e7cd70ec", - strip_prefix = "pybind11-2.10.0", - urls = ["https://github.com/pybind/pybind11/archive/v2.10.0.tar.gz"], +pip3_install( + name = "py_deps", + requirements = "//:requirements.txt", ) new_local_repository( @@ -60,16 +20,3 @@ new_local_repository( build_file = "@//bindings/python:python_headers.BUILD", path = "/usr/include/python3.6", # May be overwritten by setup.py. ) - -http_archive( - name = "rules_python", - url = "https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz", - sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0", -) - -load("@rules_python//python:pip.bzl", pip3_install="pip_install") - -pip3_install( - name = "py_deps", - requirements = "//:requirements.txt", -) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl new file mode 100644 index 0000000000..03f8ca42f9 --- /dev/null +++ b/bazel/benchmark_deps.bzl @@ -0,0 +1,65 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +def benchmark_deps(): + """Loads dependencies required to build Google Benchmark.""" + + if "bazel_skylib" not in native.existing_rules(): + http_archive( + name = "bazel_skylib", + sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + ], + ) + + if "rules_foreign_cc" not in native.existing_rules(): + http_archive( + name = "rules_foreign_cc", + sha256 = "bcd0c5f46a49b85b384906daae41d277b3dc0ff27c7c752cc51e43048a58ec83", + strip_prefix = "rules_foreign_cc-0.7.1", + url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.7.1.tar.gz", + ) + + if "rules_python" not in native.existing_rules(): + http_archive( + name = "rules_python", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz", + sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0", + ) + + if "com_google_absl" not in native.existing_rules(): + http_archive( + name = "com_google_absl", + sha256 = "f41868f7a938605c92936230081175d1eae87f6ea2c248f41077c8f88316f111", + strip_prefix = "abseil-cpp-20200225.2", + urls = ["https://github.com/abseil/abseil-cpp/archive/20200225.2.tar.gz"], + ) + + if "com_google_googletest" not in native.existing_rules(): + git_repository( + name = "com_google_googletest", + remote = "https://github.com/google/googletest.git", + tag = "release-1.11.0", + ) + + if "pybind11" not in native.existing_rules(): + http_archive( + name = "pybind11", + build_file = "@//bindings/python:pybind11.BUILD", + sha256 = "eacf582fa8f696227988d08cfc46121770823839fe9e301a20fbce67e7cd70ec", + strip_prefix = "pybind11-2.10.0", + urls = ["https://github.com/pybind/pybind11/archive/v2.10.0.tar.gz"], + ) + + if "libpfm" not in native.existing_rules(): + # Downloaded from v4.9.0 tag at https://sourceforge.net/p/perfmon2/libpfm4/ref/master/tags/ + http_archive( + name = "libpfm", + build_file = "//tools:libpfm.BUILD.bazel", + sha256 = "5da5f8872bde14b3634c9688d980f68bda28b510268723cc12973eedbab9fecc", + type = "tar.gz", + strip_prefix = "libpfm-4.11.0", + urls = ["https://sourceforge.net/projects/perfmon2/files/libpfm4/libpfm-4.11.0.tar.gz/download"], + ) \ No newline at end of file From fe5a386b403bc273ea3b6abca67a3b79bd504c22 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 19 Dec 2022 12:35:00 +0000 Subject: [PATCH 049/561] add more docs to index --- docs/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index eb82eff9ee..9cada9688b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,9 @@ * [Dependencies](dependencies.md) * [Perf Counters](perf_counters.md) * [Platform Specific Build Instructions](platform_specific_build_instructions.md) +* [Python Bindings](python_bindings.md) * [Random Interleaving](random_interleaving.md) +* [Reducing Variance](reducing_variance.md) * [Releasing](releasing.md) * [Tools](tools.md) -* [User Guide](user_guide.md) \ No newline at end of file +* [User Guide](user_guide.md) From 62edc4fb00e1aeab86cc69c70eafffb17219d047 Mon Sep 17 00:00:00 2001 From: Yury Fedorov <114264320+yuryf-google@users.noreply.github.com> Date: Mon, 19 Dec 2022 15:03:11 +0100 Subject: [PATCH 050/561] Bug fix variable 'actual_iterations' set but not used (#1517) * Bug fix variable 'actual_iterations' set but not used Compiling the project in clang 15 without -Wno-unused-but-set-variable flag the following error is generated: benchmark-src/test/options_test.cc:70:10: error: variable 'actual_iterations' set but not used [-Werror,-Wunused-but-set-variable] size_t actual_iterations = 0; ^ * Adjust according formatting of `clang-format` Co-authored-by: dominic hamon <510002+dmah42@users.noreply.github.com> --- test/options_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/options_test.cc b/test/options_test.cc index 6bba0ea846..a1b209f3eb 100644 --- a/test/options_test.cc +++ b/test/options_test.cc @@ -67,8 +67,8 @@ void BM_explicit_iteration_count(benchmark::State& state) { // Test that the requested iteration count is respected. assert(state.max_iterations == 42); - size_t actual_iterations = 0; - for (auto _ : state) ++actual_iterations; + for (auto _ : state) { + } assert(state.iterations() == state.max_iterations); assert(state.iterations() == 42); } From 37faf6f975ce7c06c5abe59795270867dc2960ca Mon Sep 17 00:00:00 2001 From: SunBlack Date: Mon, 9 Jan 2023 18:52:18 +0100 Subject: [PATCH 051/561] Fix Clang-Tidy warnings related to modernize-use-override (#1523) --- include/benchmark/benchmark.h | 76 +++++++++++++-------------- test/args_product_test.cc | 4 +- test/benchmark_setup_teardown_test.cc | 4 +- test/filter_test.cc | 6 +-- test/fixture_test.cc | 6 +-- test/map_test.cc | 4 +- test/memory_manager_test.cc | 4 +- test/multiple_ranges_test.cc | 4 +- test/output_test_helper.cc | 6 +-- test/register_benchmark_test.cc | 2 +- test/skip_with_error_test.cc | 6 +-- test/spec_arg_test.cc | 6 +-- test/time_unit_gtest.cc | 2 +- 13 files changed, 65 insertions(+), 65 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 54d4e3cf0c..d8032ec02d 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1242,7 +1242,7 @@ class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark { FunctionBenchmark(const char* name, Function* func) : Benchmark(name), func_(func) {} - virtual void Run(State& st) BENCHMARK_OVERRIDE; + void Run(State& st) BENCHMARK_OVERRIDE; private: Function* func_; @@ -1252,7 +1252,7 @@ class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark { template class LambdaBenchmark : public Benchmark { public: - virtual void Run(State& st) BENCHMARK_OVERRIDE { lambda_(st); } + void Run(State& st) BENCHMARK_OVERRIDE { lambda_(st); } private: template @@ -1302,7 +1302,7 @@ class Fixture : public internal::Benchmark { public: Fixture() : internal::Benchmark("") {} - virtual void Run(State& st) BENCHMARK_OVERRIDE { + void Run(State& st) BENCHMARK_OVERRIDE { this->SetUp(st); this->BenchmarkCase(st); this->TearDown(st); @@ -1424,37 +1424,37 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_TEMPLATE(n, a) BENCHMARK_TEMPLATE1(n, a) #endif -#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ - class BaseClass##_##Method##_Benchmark : public BaseClass { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "/" #Method); \ - } \ - \ - protected: \ - virtual void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ +#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ }; -#define BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ - class BaseClass##_##Method##_Benchmark : public BaseClass { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "<" #a ">/" #Method); \ - } \ - \ - protected: \ - virtual void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ +#define BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "<" #a ">/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ }; -#define BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ - class BaseClass##_##Method##_Benchmark : public BaseClass { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "<" #a "," #b ">/" #Method); \ - } \ - \ - protected: \ - virtual void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ +#define BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "<" #a "," #b ">/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ }; #ifdef BENCHMARK_HAS_CXX11 @@ -1466,7 +1466,7 @@ class Fixture : public internal::Benchmark { } \ \ protected: \ - virtual void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ + void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ }; #else #define BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(n, a) \ @@ -1774,8 +1774,8 @@ class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter { explicit ConsoleReporter(OutputOptions opts_ = OO_Defaults) : output_options_(opts_), name_field_width_(0), printed_header_(false) {} - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; - virtual void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; + bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; + void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; protected: virtual void PrintRunData(const Run& report); @@ -1790,9 +1790,9 @@ class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter { class BENCHMARK_EXPORT JSONReporter : public BenchmarkReporter { public: JSONReporter() : first_report_(true) {} - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; - virtual void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; - virtual void Finalize() BENCHMARK_OVERRIDE; + bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; + void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; + void Finalize() BENCHMARK_OVERRIDE; private: void PrintRunData(const Run& report); @@ -1805,8 +1805,8 @@ class BENCHMARK_EXPORT BENCHMARK_DEPRECATED_MSG( : public BenchmarkReporter { public: CSVReporter() : printed_header_(false) {} - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; - virtual void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; + bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; + void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; private: void PrintRunData(const Run& report); diff --git a/test/args_product_test.cc b/test/args_product_test.cc index d44f391f74..63b8b71e45 100644 --- a/test/args_product_test.cc +++ b/test/args_product_test.cc @@ -23,7 +23,7 @@ class ArgsProductFixture : public ::benchmark::Fixture { {2, 15, 10, 9}, {4, 5, 6, 11}}) {} - void SetUp(const ::benchmark::State& state) BENCHMARK_OVERRIDE { + void SetUp(const ::benchmark::State& state) override { std::vector ranges = {state.range(0), state.range(1), state.range(2), state.range(3)}; @@ -34,7 +34,7 @@ class ArgsProductFixture : public ::benchmark::Fixture { // NOTE: This is not TearDown as we want to check after _all_ runs are // complete. - virtual ~ArgsProductFixture() { + ~ArgsProductFixture() override { if (actualValues != expectedValues) { std::cout << "EXPECTED\n"; for (const auto& v : expectedValues) { diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index f67175953a..a2cb82a902 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -80,11 +80,11 @@ int fixture_setup = 0; class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture { public: - void SetUp(const ::benchmark::State&) BENCHMARK_OVERRIDE { + void SetUp(const ::benchmark::State&) override { fixture_interaction::fixture_setup++; } - ~FIXTURE_BECHMARK_NAME() {} + ~FIXTURE_BECHMARK_NAME() override {} }; BENCHMARK_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)(benchmark::State& st) { diff --git a/test/filter_test.cc b/test/filter_test.cc index 266584a0f1..4c8b8ea488 100644 --- a/test/filter_test.cc +++ b/test/filter_test.cc @@ -14,11 +14,11 @@ namespace { class TestReporter : public benchmark::ConsoleReporter { public: - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + bool ReportContext(const Context& context) override { return ConsoleReporter::ReportContext(context); }; - virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + void ReportRuns(const std::vector& report) override { ++count_; max_family_index_ = std::max(max_family_index_, report[0].family_index); ConsoleReporter::ReportRuns(report); @@ -26,7 +26,7 @@ class TestReporter : public benchmark::ConsoleReporter { TestReporter() : count_(0), max_family_index_(0) {} - virtual ~TestReporter() {} + ~TestReporter() override {} int GetCount() const { return count_; } diff --git a/test/fixture_test.cc b/test/fixture_test.cc index af650dbd06..d1093ebf52 100644 --- a/test/fixture_test.cc +++ b/test/fixture_test.cc @@ -8,21 +8,21 @@ class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture { public: - void SetUp(const ::benchmark::State& state) BENCHMARK_OVERRIDE { + void SetUp(const ::benchmark::State& state) override { if (state.thread_index() == 0) { assert(data.get() == nullptr); data.reset(new int(42)); } } - void TearDown(const ::benchmark::State& state) BENCHMARK_OVERRIDE { + void TearDown(const ::benchmark::State& state) override { if (state.thread_index() == 0) { assert(data.get() != nullptr); data.reset(); } } - ~FIXTURE_BECHMARK_NAME() { assert(data == nullptr); } + ~FIXTURE_BECHMARK_NAME() override { assert(data == nullptr); } std::unique_ptr data; }; diff --git a/test/map_test.cc b/test/map_test.cc index 509613457c..1979fcb829 100644 --- a/test/map_test.cc +++ b/test/map_test.cc @@ -34,11 +34,11 @@ BENCHMARK(BM_MapLookup)->Range(1 << 3, 1 << 12); // Using fixtures. class MapFixture : public ::benchmark::Fixture { public: - void SetUp(const ::benchmark::State& st) BENCHMARK_OVERRIDE { + void SetUp(const ::benchmark::State& st) override { m = ConstructRandomMap(static_cast(st.range(0))); } - void TearDown(const ::benchmark::State&) BENCHMARK_OVERRIDE { m.clear(); } + void TearDown(const ::benchmark::State&) override { m.clear(); } std::map m; }; diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index 4b08f3f77b..7cf107fc23 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -5,8 +5,8 @@ #include "output_test.h" class TestMemoryManager : public benchmark::MemoryManager { - void Start() BENCHMARK_OVERRIDE {} - void Stop(Result& result) BENCHMARK_OVERRIDE { + void Start() override {} + void Stop(Result& result) override { result.num_allocs = 42; result.max_bytes_used = 42000; } diff --git a/test/multiple_ranges_test.cc b/test/multiple_ranges_test.cc index 7618c4da08..5300a96036 100644 --- a/test/multiple_ranges_test.cc +++ b/test/multiple_ranges_test.cc @@ -28,7 +28,7 @@ class MultipleRangesFixture : public ::benchmark::Fixture { {2, 7, 15}, {7, 6, 3}}) {} - void SetUp(const ::benchmark::State& state) BENCHMARK_OVERRIDE { + void SetUp(const ::benchmark::State& state) override { std::vector ranges = {state.range(0), state.range(1), state.range(2)}; @@ -39,7 +39,7 @@ class MultipleRangesFixture : public ::benchmark::Fixture { // NOTE: This is not TearDown as we want to check after _all_ runs are // complete. - virtual ~MultipleRangesFixture() { + ~MultipleRangesFixture() override { if (actualValues != expectedValues) { std::cout << "EXPECTED\n"; for (const auto& v : expectedValues) { diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index 81584cbf77..a4765ae09b 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -143,7 +143,7 @@ class TestReporter : public benchmark::BenchmarkReporter { TestReporter(std::vector reps) : reporters_(std::move(reps)) {} - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + bool ReportContext(const Context& context) override { bool last_ret = false; bool first = true; for (auto rep : reporters_) { @@ -157,10 +157,10 @@ class TestReporter : public benchmark::BenchmarkReporter { return last_ret; } - void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + void ReportRuns(const std::vector& report) override { for (auto rep : reporters_) rep->ReportRuns(report); } - void Finalize() BENCHMARK_OVERRIDE { + void Finalize() override { for (auto rep : reporters_) rep->Finalize(); } diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index 37dbba6b95..240c8c2447 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -10,7 +10,7 @@ namespace { class TestReporter : public benchmark::ConsoleReporter { public: - virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + void ReportRuns(const std::vector& report) override { all_runs_.insert(all_runs_.end(), begin(report), end(report)); ConsoleReporter::ReportRuns(report); } diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 026d479133..61691ec73e 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -10,17 +10,17 @@ namespace { class TestReporter : public benchmark::ConsoleReporter { public: - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + bool ReportContext(const Context& context) override { return ConsoleReporter::ReportContext(context); }; - virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + void ReportRuns(const std::vector& report) override { all_runs_.insert(all_runs_.end(), begin(report), end(report)); ConsoleReporter::ReportRuns(report); } TestReporter() {} - virtual ~TestReporter() {} + ~TestReporter() override {} mutable std::vector all_runs_; }; diff --git a/test/spec_arg_test.cc b/test/spec_arg_test.cc index 68ab1351b3..06aafbeb9b 100644 --- a/test/spec_arg_test.cc +++ b/test/spec_arg_test.cc @@ -17,11 +17,11 @@ namespace { class TestReporter : public benchmark::ConsoleReporter { public: - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + bool ReportContext(const Context& context) override { return ConsoleReporter::ReportContext(context); }; - virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + void ReportRuns(const std::vector& report) override { assert(report.size() == 1); matched_functions.push_back(report[0].run_name.function_name); ConsoleReporter::ReportRuns(report); @@ -29,7 +29,7 @@ class TestReporter : public benchmark::ConsoleReporter { TestReporter() {} - virtual ~TestReporter() {} + ~TestReporter() override {} const std::vector& GetMatchedFunctions() const { return matched_functions; diff --git a/test/time_unit_gtest.cc b/test/time_unit_gtest.cc index ae53743285..484ecbcfb4 100644 --- a/test/time_unit_gtest.cc +++ b/test/time_unit_gtest.cc @@ -9,7 +9,7 @@ namespace { class DummyBenchmark : public Benchmark { public: DummyBenchmark() : Benchmark("dummy") {} - virtual void Run(State&) override {} + void Run(State&) override {} }; TEST(DefaultTimeUnitTest, TimeUnitIsNotSet) { From fe65457e80ef8ab6bbd6da418ab7cb6f6102afda Mon Sep 17 00:00:00 2001 From: SunBlack Date: Tue, 10 Jan 2023 13:25:32 +0100 Subject: [PATCH 052/561] Fix typos found by codespell (#1519) --- CMakeLists.txt | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- bindings/python/google_benchmark/example.py | 2 +- docs/perf_counters.md | 2 +- docs/reducing_variance.md | 2 +- include/benchmark/benchmark.h | 2 +- src/benchmark.cc | 4 ++-- src/complexity.h | 2 +- src/console_reporter.cc | 2 +- src/perf_counters.cc | 2 +- src/statistics.h | 7 ++++--- src/sysinfo.cc | 2 +- test/benchmark_setup_teardown_test.cc | 2 +- tools/gbench/util.py | 2 +- 14 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b9dd38e89..f7a17d8e51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -236,7 +236,7 @@ else() # On most UNIX like platforms g++ and clang++ define _GNU_SOURCE as a # predefined macro, which turns on all of the wonderful libc extensions. - # However g++ doesn't do this in Cygwin so we have to define it ourselfs + # However g++ doesn't do this in Cygwin so we have to define it ourselves # since we depend on GNU/POSIX/BSD extensions. if (CYGWIN) add_definitions(-D_GNU_SOURCE=1) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 10f5d5ddea..e6ef8e7d3c 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -104,7 +104,7 @@ def __decorator(func_or_options): options = self.make(func_or_options) options.builder_calls.append((builder_name, args, kwargs)) # The decorator returns Options so it is not technically a decorator - # and needs a final call to @regiser + # and needs a final call to @register return options return __decorator diff --git a/bindings/python/google_benchmark/example.py b/bindings/python/google_benchmark/example.py index 487acc9f1e..d95a0438d6 100644 --- a/bindings/python/google_benchmark/example.py +++ b/bindings/python/google_benchmark/example.py @@ -72,7 +72,7 @@ def manual_timing(state): @benchmark.register def custom_counters(state): - """Collect cutom metric using benchmark.Counter.""" + """Collect custom metric using benchmark.Counter.""" num_foo = 0.0 while state: # Benchmark some code here diff --git a/docs/perf_counters.md b/docs/perf_counters.md index db83145c9a..f342092c99 100644 --- a/docs/perf_counters.md +++ b/docs/perf_counters.md @@ -19,7 +19,7 @@ The feature does not require modifying benchmark code. Counter collection is handled at the boundaries where timer collection is also handled. To opt-in: -* If using a Bazel build, add `--define pfm=1` to your buid flags +* If using a Bazel build, add `--define pfm=1` to your build flags * If using CMake: * Install `libpfm4-dev`, e.g. `apt-get install libpfm4-dev`. * Enable the CMake flag `BENCHMARK_ENABLE_LIBPFM` in `CMakeLists.txt`. diff --git a/docs/reducing_variance.md b/docs/reducing_variance.md index f8b757580d..e566ab9852 100644 --- a/docs/reducing_variance.md +++ b/docs/reducing_variance.md @@ -70,7 +70,7 @@ reason some companies maintain machines dedicated to performance testing. Some of the easier and and effective ways of reducing variance on a typical Linux workstation are: -1. Use the performance governer as [discussed +1. Use the performance governor as [discussed above](user_guide#disabling-cpu-frequency-scaling). 1. Disable processor boosting by: ```sh diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index d8032ec02d..eb29ca50b6 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1845,7 +1845,7 @@ inline double GetTimeUnitMultiplier(TimeUnit unit) { // Creates a list of integer values for the given range and multiplier. // This can be used together with ArgsProduct() to allow multiple ranges -// with different multiplers. +// with different multipliers. // Example: // ArgsProduct({ // CreateRange(0, 1024, /*multi=*/32), diff --git a/src/benchmark.cc b/src/benchmark.cc index 12b2d16d24..ec729f7ad2 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -73,8 +73,8 @@ BM_DEFINE_string(benchmark_filter, ""); BM_DEFINE_double(benchmark_min_time, 0.5); // Minimum number of seconds a benchmark should be run before results should be -// taken into account. This e.g can be neccessary for benchmarks of code which -// needs to fill some form of cache before performance is of interrest. +// taken into account. This e.g can be necessary for benchmarks of code which +// needs to fill some form of cache before performance is of interest. // Note: results gathered within this period are discarded and not used for // reported result. BM_DEFINE_double(benchmark_min_warmup_time, 0.0); diff --git a/src/complexity.h b/src/complexity.h index df29b48d29..0a0679b48b 100644 --- a/src/complexity.h +++ b/src/complexity.h @@ -31,7 +31,7 @@ std::vector ComputeBigO( const std::vector& reports); // This data structure will contain the result returned by MinimalLeastSq -// - coef : Estimated coeficient for the high-order term as +// - coef : Estimated coefficient for the high-order term as // interpolated from data. // - rms : Normalized Root Mean Squared Error. // - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 3950e49814..f3d81b253b 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -115,7 +115,7 @@ static std::string FormatTime(double time) { if (time < 100.0) { return FormatString("%10.1f", time); } - // Assuming the time ist at max 9.9999e+99 and we have 10 digits for the + // Assuming the time is at max 9.9999e+99 and we have 10 digits for the // number, we get 10-1(.)-1(e)-1(sign)-2(exponent) = 5 digits to print. if (time > 9999999999 /*max 10 digit number*/) { return FormatString("%1.4e", time); diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 582475f0ba..06351b694d 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -68,7 +68,7 @@ PerfCounters PerfCounters::Create( return NoCounters(); } attr.disabled = is_first; - // Note: the man page for perf_event_create suggests inerit = true and + // Note: the man page for perf_event_create suggests inherit = true and // read_format = PERF_FORMAT_GROUP don't work together, but that's not the // case. attr.inherit = true; diff --git a/src/statistics.h b/src/statistics.h index b0d2c05e72..6e5560e8f1 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -22,9 +22,10 @@ namespace benchmark { -// Return a vector containing the mean, median and standard devation information -// (and any user-specified info) for the specified list of reports. If 'reports' -// contains less than two non-errored runs an empty vector is returned +// Return a vector containing the mean, median and standard deviation +// information (and any user-specified info) for the specified list of reports. +// If 'reports' contains less than two non-errored runs an empty vector is +// returned BENCHMARK_EXPORT std::vector ComputeStats( const std::vector& reports); diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 41c0f9f954..59120b72b4 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -441,7 +441,7 @@ std::string GetSystemName() { return str; #else #ifndef HOST_NAME_MAX -#ifdef BENCHMARK_HAS_SYSCTL // BSD/Mac Doesnt have HOST_NAME_MAX defined +#ifdef BENCHMARK_HAS_SYSCTL // BSD/Mac doesn't have HOST_NAME_MAX defined #define HOST_NAME_MAX 64 #elif defined(BENCHMARK_OS_NACL) #define HOST_NAME_MAX 64 diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index a2cb82a902..6c3cc2e58f 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -145,7 +145,7 @@ int main(int argc, char** argv) { // Setup is called 4 times, once for each arg group (1,3,5,7) assert(fixture_interaction::setup == 4); - // Fixture::Setup is called everytime the bm routine is run. + // Fixture::Setup is called every time the bm routine is run. // The exact number is indeterministic, so we just assert that // it's more than setup. assert(fixture_interaction::fixture_setup > fixture_interaction::setup); diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 5d0012c0cb..95d7994b3e 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -58,7 +58,7 @@ def classify_input_file(filename): """ Return a tuple (type, msg) where 'type' specifies the classified type of 'filename'. If 'type' is 'IT_Invalid' then 'msg' is a human readable - string represeting the error. + string representing the error. """ ftype = IT_Invalid err_msg = None From a3235d7b69c84e8c9ff8722a22b8ac5e1bc716a6 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 10 Jan 2023 11:48:17 -0500 Subject: [PATCH 053/561] Include the benchmark's family-name in State (#1511) * Include the benchmark's family-name in State For compat with internal library, where State::name() returns the benchmark's family name. * added missing files from prev commit * fix field-init order error * added test --- include/benchmark/benchmark.h | 10 +++++++--- src/benchmark.cc | 7 ++++--- src/benchmark_api_internal.cc | 12 ++++++------ test/benchmark_test.cc | 9 +++++++++ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index eb29ca50b6..e8b1a7d6d4 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -825,6 +825,9 @@ class BENCHMARK_EXPORT State { return max_iterations - total_iterations_ + batch_leftover_; } + BENCHMARK_ALWAYS_INLINE + std::string name() const { return name_; } + private: // items we expect on the first cache line (ie 64 bytes of the struct) // When total_iterations_ is 0, KeepRunning() and friends will return false. @@ -854,9 +857,9 @@ class BENCHMARK_EXPORT State { UserCounters counters; private: - State(IterationCount max_iters, const std::vector& ranges, - int thread_i, int n_threads, internal::ThreadTimer* timer, - internal::ThreadManager* manager, + State(std::string name, IterationCount max_iters, + const std::vector& ranges, int thread_i, int n_threads, + internal::ThreadTimer* timer, internal::ThreadManager* manager, internal::PerfCountersMeasurement* perf_counters_measurement); void StartKeepRunning(); @@ -865,6 +868,7 @@ class BENCHMARK_EXPORT State { bool KeepRunningInternal(IterationCount n, bool is_batch); void FinishKeepRunning(); + const std::string name_; const int thread_index_; const int threads_; diff --git a/src/benchmark.cc b/src/benchmark.cc index ec729f7ad2..539f0de429 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -148,9 +148,9 @@ void UseCharPointer(char const volatile*) {} } // namespace internal -State::State(IterationCount max_iters, const std::vector& ranges, - int thread_i, int n_threads, internal::ThreadTimer* timer, - internal::ThreadManager* manager, +State::State(std::string name, IterationCount max_iters, + const std::vector& ranges, int thread_i, int n_threads, + internal::ThreadTimer* timer, internal::ThreadManager* manager, internal::PerfCountersMeasurement* perf_counters_measurement) : total_iterations_(0), batch_leftover_(0), @@ -160,6 +160,7 @@ State::State(IterationCount max_iters, const std::vector& ranges, error_occurred_(false), range_(ranges), complexity_n_(0), + name_(std::move(name)), thread_index_(thread_i), threads_(n_threads), timer_(timer), diff --git a/src/benchmark_api_internal.cc b/src/benchmark_api_internal.cc index 963fea22f3..286f986530 100644 --- a/src/benchmark_api_internal.cc +++ b/src/benchmark_api_internal.cc @@ -93,24 +93,24 @@ State BenchmarkInstance::Run( IterationCount iters, int thread_id, internal::ThreadTimer* timer, internal::ThreadManager* manager, internal::PerfCountersMeasurement* perf_counters_measurement) const { - State st(iters, args_, thread_id, threads_, timer, manager, - perf_counters_measurement); + State st(name_.function_name, iters, args_, thread_id, threads_, timer, + manager, perf_counters_measurement); benchmark_.Run(st); return st; } void BenchmarkInstance::Setup() const { if (setup_) { - State st(/*iters*/ 1, args_, /*thread_id*/ 0, threads_, nullptr, nullptr, - nullptr); + State st(name_.function_name, /*iters*/ 1, args_, /*thread_id*/ 0, threads_, + nullptr, nullptr, nullptr); setup_(st); } } void BenchmarkInstance::Teardown() const { if (teardown_) { - State st(/*iters*/ 1, args_, /*thread_id*/ 0, threads_, nullptr, nullptr, - nullptr); + State st(name_.function_name, /*iters*/ 1, args_, /*thread_id*/ 0, threads_, + nullptr, nullptr, nullptr); teardown_(st); } } diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index 47023a7eba..bd6005d194 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -245,4 +245,13 @@ BENCHMARK(BM_DenseThreadRanges)->Arg(1)->DenseThreadRange(1, 3); BENCHMARK(BM_DenseThreadRanges)->Arg(2)->DenseThreadRange(1, 4, 2); BENCHMARK(BM_DenseThreadRanges)->Arg(3)->DenseThreadRange(5, 14, 3); +static void BM_BenchmarkName(benchmark::State& state) { + for (auto _ : state) { + } + + // Check that the benchmark name is passed correctly to `state`. + assert("BM_BenchmarkName" == state.name()); +} +BENCHMARK(BM_BenchmarkName); + BENCHMARK_MAIN(); From cfbc94960f4b65ff7fe9d825ad12677dbd164026 Mon Sep 17 00:00:00 2001 From: SunBlack Date: Mon, 16 Jan 2023 13:28:48 +0100 Subject: [PATCH 054/561] Fix Clang-Tidy warnings readability-else-after-return (#1528) --- src/benchmark.cc | 23 ++++++++++++++--------- src/colorprint.cc | 18 +++++++++--------- src/commandlineflags.cc | 7 ++++--- src/string_util.cc | 6 +++--- test/output_test_helper.cc | 17 +++++++++-------- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 539f0de429..8e7408f8fa 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -410,14 +410,15 @@ std::unique_ptr CreateReporter( typedef std::unique_ptr PtrType; if (name == "console") { return PtrType(new ConsoleReporter(output_opts)); - } else if (name == "json") { + } + if (name == "json") { return PtrType(new JSONReporter()); - } else if (name == "csv") { + } + if (name == "csv") { return PtrType(new CSVReporter()); - } else { - std::cerr << "Unexpected format: '" << name << "'\n"; - std::exit(1); } + std::cerr << "Unexpected format: '" << name << "'\n"; + std::exit(1); } BENCHMARK_RESTORE_DEPRECATED_WARNING @@ -586,13 +587,17 @@ void PrintUsageAndExit() { void SetDefaultTimeUnitFromFlag(const std::string& time_unit_flag) { if (time_unit_flag == "s") { return SetDefaultTimeUnit(kSecond); - } else if (time_unit_flag == "ms") { + } + if (time_unit_flag == "ms") { return SetDefaultTimeUnit(kMillisecond); - } else if (time_unit_flag == "us") { + } + if (time_unit_flag == "us") { return SetDefaultTimeUnit(kMicrosecond); - } else if (time_unit_flag == "ns") { + } + if (time_unit_flag == "ns") { return SetDefaultTimeUnit(kNanosecond); - } else if (!time_unit_flag.empty()) { + } + if (!time_unit_flag.empty()) { PrintUsageAndExit(); } } diff --git a/src/colorprint.cc b/src/colorprint.cc index 1a000a0637..62e9310a12 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -96,18 +96,18 @@ std::string FormatString(const char* msg, va_list args) { // currently there is no error handling for failure, so this is hack. BM_CHECK(ret >= 0); - if (ret == 0) // handle empty expansion + if (ret == 0) { // handle empty expansion return {}; - else if (static_cast(ret) < size) + } + if (static_cast(ret) < size) { return local_buff; - else { - // we did not provide a long enough buffer on our first attempt. - size = static_cast(ret) + 1; // + 1 for the null byte - std::unique_ptr buff(new char[size]); - ret = vsnprintf(buff.get(), size, msg, args); - BM_CHECK(ret > 0 && (static_cast(ret)) < size); - return buff.get(); } + // we did not provide a long enough buffer on our first attempt. + size = static_cast(ret) + 1; // + 1 for the null byte + std::unique_ptr buff(new char[size]); + ret = vsnprintf(buff.get(), size, msg, args); + BM_CHECK(ret > 0 && (static_cast(ret)) < size); + return buff.get(); } std::string FormatString(const char* msg, ...) { diff --git a/src/commandlineflags.cc b/src/commandlineflags.cc index 1f555b2757..dcb414959d 100644 --- a/src/commandlineflags.cc +++ b/src/commandlineflags.cc @@ -284,14 +284,15 @@ bool IsTruthyFlagValue(const std::string& value) { char v = value[0]; return isalnum(v) && !(v == '0' || v == 'f' || v == 'F' || v == 'n' || v == 'N'); - } else if (!value.empty()) { + } + if (!value.empty()) { std::string value_lower(value); std::transform(value_lower.begin(), value_lower.end(), value_lower.begin(), [](char c) { return static_cast(::tolower(c)); }); return !(value_lower == "false" || value_lower == "no" || value_lower == "off"); - } else - return true; + } + return true; } } // end namespace benchmark diff --git a/src/string_util.cc b/src/string_util.cc index b3196fc266..5e2d24a3cd 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -94,10 +94,10 @@ std::string ExponentToPrefix(int64_t exponent, bool iec) { const char* array = (exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits); - if (iec) + if (iec) { return array[index] + std::string("i"); - else - return std::string(1, array[index]); + } + return std::string(1, array[index]); } std::string ToBinaryStringFullySpecified(double value, double threshold, diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index a4765ae09b..986c4adbed 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -248,9 +248,8 @@ void ResultsChecker::CheckResults(std::stringstream& output) { if (!p.regex->Match(r.name)) { BM_VLOG(2) << p.regex_str << " is not matched by " << r.name << "\n"; continue; - } else { - BM_VLOG(2) << p.regex_str << " is matched by " << r.name << "\n"; } + BM_VLOG(2) << p.regex_str << " is matched by " << r.name << "\n"; BM_VLOG(1) << "Checking results of " << r.name << ": ... \n"; p.fn(r); BM_VLOG(1) << "Checking results of " << r.name << ": OK.\n"; @@ -328,16 +327,18 @@ double Results::GetTime(BenchmarkTime which) const { BM_CHECK(unit); if (*unit == "ns") { return val * 1.e-9; - } else if (*unit == "us") { + } + if (*unit == "us") { return val * 1.e-6; - } else if (*unit == "ms") { + } + if (*unit == "ms") { return val * 1.e-3; - } else if (*unit == "s") { + } + if (*unit == "s") { return val; - } else { - BM_CHECK(1 == 0) << "unknown time unit: " << *unit; - return 0; } + BM_CHECK(1 == 0) << "unknown time unit: " << *unit; + return 0; } // ========================================================================= // From 5e78bedfb07c615edb2b646d1e354980268c1728 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 17 Jan 2023 09:18:57 -0500 Subject: [PATCH 055/561] Add quick instructions on how to enable sans checks (#1529) Co-authored-by: dominic hamon <510002+dmah42@users.noreply.github.com> --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 205fb008af..03d5dc31f2 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,12 @@ cache variables, if autodetection fails. If you are using clang, you may need to set `LLVMAR_EXECUTABLE`, `LLVMNM_EXECUTABLE` and `LLVMRANLIB_EXECUTABLE` cmake cache variables. +To enable sanitizer checks (eg., `asan` and `tsan`), add: +``` + -DCMAKE_C_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=address -fsanitize=thread -fno-sanitize-recover=all" + -DCMAKE_CXX_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=address -fsanitize=thread -fno-sanitize-recover=all " +``` + ### Stable and Experimental Library Versions The main branch contains the latest stable version of the benchmarking library; From f59d021ebc9631a4eee574192d09ace8be666a85 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Fri, 3 Feb 2023 10:47:02 +0100 Subject: [PATCH 056/561] Modernize setup.py, extend Python bindings CI (#1535) distutils is deprecated and will be removed in Python 3.12, so this commit modernizes the Python bindings `setup.py` file in order to future-proof the code. On top of this, type hints were added for all of the convenience functions to make static type checking adoption easier in the future, if desired. A context manager was added to temporarily write the Python include path to the Bazel WORKSPACE file - but unlike previously, the WORKSPACE file is reverted to its previous state after the build to not produce changes on every rebuild. Lastly, the Python bindings test matrix was extended to all major platforms to create a more complete picture of the current state of the bindings, especially with regards to upcoming wheel builds. --- .github/workflows/test_bindings.yml | 18 ++-- WORKSPACE | 2 +- setup.py | 155 ++++++++++++++-------------- 3 files changed, 89 insertions(+), 86 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 4a580ebe04..c0e1c9af2b 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -8,17 +8,21 @@ on: jobs: python_bindings: - runs-on: ubuntu-latest + name: Test GBM Python bindings on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: - python-version: 3.8 - - name: Install benchmark + python-version: 3.11 + - name: Install GBM Python bindings on ${{ matrix.os}} run: - python setup.py install - - name: Run example bindings + python -m pip install wheel . + - name: Run bindings example on ${{ matrix.os }} run: python bindings/python/google_benchmark/example.py diff --git a/WORKSPACE b/WORKSPACE index 6dab3d951d..74e7ebcbe9 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -18,5 +18,5 @@ pip3_install( new_local_repository( name = "python_headers", build_file = "@//bindings/python:python_headers.BUILD", - path = "/usr/include/python3.6", # May be overwritten by setup.py. + path = "", # May be overwritten by setup.py. ) diff --git a/setup.py b/setup.py index e9d598a0f9..0f48636237 100644 --- a/setup.py +++ b/setup.py @@ -1,44 +1,38 @@ +import contextlib import os -import posixpath import platform -import re import shutil -import sys +import sysconfig +from pathlib import Path +from typing import List -from distutils import sysconfig import setuptools from setuptools.command import build_ext -HERE = os.path.dirname(os.path.abspath(__file__)) +PYTHON_INCLUDE_PATH_PLACEHOLDER = "" +IS_WINDOWS = platform.system() == "Windows" +IS_MAC = platform.system() == "Darwin" -IS_WINDOWS = sys.platform.startswith("win") +def _get_long_description(fp: str) -> str: + with open(fp, "r", encoding="utf-8") as f: + return f.read() -with open("README.md", "r", encoding="utf-8") as fp: - long_description = fp.read() - -def _get_version(): - """Parse the version string from __init__.py.""" - with open( - os.path.join(HERE, "bindings", "python", "google_benchmark", "__init__.py") - ) as init_file: - try: - version_line = next( - line for line in init_file if line.startswith("__version__") - ) - except StopIteration: - raise ValueError("__version__ not defined in __init__.py") - else: - namespace = {} - exec(version_line, namespace) # pylint: disable=exec-used - return namespace["__version__"] +def _get_version(fp: str) -> str: + """Parse a version string from a file.""" + with open(fp, "r") as f: + for line in f: + if "__version__" in line: + delim = '"' + return line.split(delim)[1] + raise RuntimeError(f"could not find a version string in file {fp!r}.") -def _parse_requirements(path): - with open(os.path.join(HERE, path)) as requirements: +def _parse_requirements(fp: str) -> List[str]: + with open(fp) as requirements: return [ line.rstrip() for line in requirements @@ -46,15 +40,36 @@ def _parse_requirements(path): ] +@contextlib.contextmanager +def temp_fill_include_path(fp: str): + """Temporarily set the Python include path in a file.""" + with open(fp, "r+") as f: + try: + content = f.read() + replaced = content.replace( + PYTHON_INCLUDE_PATH_PLACEHOLDER, + Path(sysconfig.get_paths()['include']).as_posix(), + ) + f.seek(0) + f.write(replaced) + f.truncate() + yield + finally: + # revert to the original content after exit + f.seek(0) + f.write(content) + f.truncate() + + class BazelExtension(setuptools.Extension): """A C/C++ extension that is defined as a Bazel BUILD target.""" - def __init__(self, name, bazel_target): + def __init__(self, name: str, bazel_target: str): + super().__init__(name=name, sources=[]) + self.bazel_target = bazel_target - self.relpath, self.target_name = posixpath.relpath(bazel_target, "//").split( - ":" - ) - setuptools.Extension.__init__(self, name, sources=[]) + stripped_target = bazel_target.split("//")[-1] + self.relpath, self.target_name = stripped_target.split(":") class BuildBazelExtension(build_ext.build_ext): @@ -65,67 +80,51 @@ def run(self): self.bazel_build(ext) build_ext.build_ext.run(self) - def bazel_build(self, ext): + def bazel_build(self, ext: BazelExtension): """Runs the bazel build to create the package.""" - with open("WORKSPACE", "r") as workspace: - workspace_contents = workspace.read() - - with open("WORKSPACE", "w") as workspace: - workspace.write( - re.sub( - r'(?<=path = ").*(?=", # May be overwritten by setup\.py\.)', - sysconfig.get_python_inc().replace(os.path.sep, posixpath.sep), - workspace_contents, - ) - ) - - if not os.path.exists(self.build_temp): - os.makedirs(self.build_temp) + with temp_fill_include_path("WORKSPACE"): + temp_path = Path(self.build_temp) - bazel_argv = [ - "bazel", - "build", - ext.bazel_target, - "--symlink_prefix=" + os.path.join(self.build_temp, "bazel-"), - "--compilation_mode=" + ("dbg" if self.debug else "opt"), - ] + bazel_argv = [ + "bazel", + "build", + str(ext.bazel_target), + f"--symlink_prefix={temp_path / 'bazel-'}", + f"--compilation_mode={'dbg' if self.debug else 'opt'}", + ] - if IS_WINDOWS: - # Link with python*.lib. - for library_dir in self.library_dirs: - bazel_argv.append("--linkopt=/LIBPATH:" + library_dir) - elif sys.platform == "darwin" and platform.machine() == "x86_64": - bazel_argv.append("--macos_minimum_os=10.9") + if IS_WINDOWS: + # Link with python*.lib. + for library_dir in self.library_dirs: + bazel_argv.append("--linkopt=/LIBPATH:" + library_dir) + elif IS_MAC and platform.machine() == "x86_64": + bazel_argv.append("--macos_minimum_os=10.9") - # ARCHFLAGS is always set by cibuildwheel before macOS wheel builds. - archflags = os.getenv("ARCHFLAGS", "") - if "arm64" in archflags: - bazel_argv.append("--cpu=darwin_arm64") - bazel_argv.append("--macos_cpus=arm64") + # ARCHFLAGS is always set by cibuildwheel before macOS wheel builds. + archflags = os.getenv("ARCHFLAGS", "") + if "arm64" in archflags: + bazel_argv.append("--cpu=darwin_arm64") + bazel_argv.append("--macos_cpus=arm64") - self.spawn(bazel_argv) + self.spawn(bazel_argv) - shared_lib_suffix = '.dll' if IS_WINDOWS else '.so' - ext_bazel_bin_path = os.path.join( - self.build_temp, 'bazel-bin', - ext.relpath, ext.target_name + shared_lib_suffix) + shared_lib_suffix = '.dll' if IS_WINDOWS else '.so' + ext_name = ext.target_name + shared_lib_suffix + ext_bazel_bin_path = temp_path / 'bazel-bin' / ext.relpath / ext_name - ext_dest_path = self.get_ext_fullpath(ext.name) - ext_dest_dir = os.path.dirname(ext_dest_path) - if not os.path.exists(ext_dest_dir): - os.makedirs(ext_dest_dir) - shutil.copyfile(ext_bazel_bin_path, ext_dest_path) + ext_dest_path = Path(self.get_ext_fullpath(ext.name)) + shutil.copyfile(ext_bazel_bin_path, ext_dest_path) - # explicitly call `bazel shutdown` for graceful exit - self.spawn(["bazel", "shutdown"]) + # explicitly call `bazel shutdown` for graceful exit + self.spawn(["bazel", "shutdown"]) setuptools.setup( name="google_benchmark", - version=_get_version(), + version=_get_version("bindings/python/google_benchmark/__init__.py"), url="https://github.com/google/benchmark", description="A library to benchmark code snippets.", - long_description=long_description, + long_description=_get_long_description("README.md"), long_description_content_type="text/markdown", author="Google", author_email="benchmark-py@google.com", From 80a3c5e4d9e5330aa4b888236c40e0c1bff3d275 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 6 Feb 2023 14:07:17 +0100 Subject: [PATCH 057/561] Switch bindings implementation to `nanobind` (#1526) * End support for Python 3.7, update cibuildwheel and publish actions Removes Python 3.7 from the support matrix, since it does not support PEP590 vectorcalls. Bumps the `cibuildwheel` and `pypa-publish` actions to their latest available versions respectively. * Add nanobind to the Bazel dependencies, add a BUILD file The build file builds nanobind as a static `cc_library`. Currently, the git SHA points to HEAD, since some necessary features have not been included in a release yet. * Delete pybind11 BUILD file * Switch bindings implementation to nanobind Switches over the binding tool to `nanobind` from `pybind11`. Most changes in the build setup itself were drop-in replacements of existing code changed to nanobind names, no new concepts needed to be implemented. Sets the minimum required macOS to 10.14 for full C++17 support. Also, to avoid ambiguities in Bazel, build for macOS 11 on Mac ARM64. * Use Bazel select for linker options Guards against unknown linker option errors by selecting required linker options for nanobind only on macOS, where they are relevant. Other changes: * Bump cibuildwheel action to v2.12.0 * Bump Bazel for aarch64 linux wheels to 6.0.0 * Remove C++17 flag from build files since it is present in setup.py `bazel build` command * Bump nanobind commit to current HEAD (TBD: Bump to next stable release) * Unbreak Windows builds of nanobind-based bindings Guards compiler options behind a new `select` macro choosing between MSVC and not MSVC. Other changes: * Inject the proper C++17 standard cxxopt in the `setup.py` build command. * Bump nanobind to current HEAD. * Make `macos` a benchmark-wide condition, with public visibility to allow its use in the nanobind BUILD file. * Fall back to `nb::implicitly_convertible` for Counter construction Since `benchmark::Counter` only has a constructor for `double`, the nanobind `nb::init_implicit` template cannot be used. Therefore, to support implicit construction from ints, we fall back to the `nb::implicitly_convertible` template instead. --- .github/install_bazel.sh | 2 +- .github/workflows/test_bindings.yml | 1 + .github/workflows/wheels.yml | 16 +-- BUILD.bazel | 6 + bazel/benchmark_deps.bzl | 14 +-- bindings/python/google_benchmark/BUILD | 8 +- bindings/python/google_benchmark/benchmark.cc | 116 +++++++++--------- bindings/python/nanobind.BUILD | 52 ++++++++ bindings/python/pybind11.BUILD | 20 --- setup.py | 25 ++-- 10 files changed, 154 insertions(+), 106 deletions(-) create mode 100644 bindings/python/nanobind.BUILD delete mode 100644 bindings/python/pybind11.BUILD diff --git a/.github/install_bazel.sh b/.github/install_bazel.sh index afdd8db8ac..bb910d8b57 100644 --- a/.github/install_bazel.sh +++ b/.github/install_bazel.sh @@ -5,7 +5,7 @@ if ! bazel version; then fi echo "Installing wget and downloading $arch Bazel binary from GitHub releases." yum install -y wget - wget "https://github.com/bazelbuild/bazel/releases/download/5.2.0/bazel-5.2.0-linux-$arch" -O /usr/local/bin/bazel + wget "https://github.com/bazelbuild/bazel/releases/download/6.0.0/bazel-6.0.0-linux-$arch" -O /usr/local/bin/bazel chmod +x /usr/local/bin/bazel else # bazel is installed for the correct architecture diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index c0e1c9af2b..98fa7e1cac 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -11,6 +11,7 @@ jobs: name: Test GBM Python bindings on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e8c8074018..d3c4630e1a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -14,10 +14,10 @@ jobs: - name: Check out repo uses: actions/checkout@v3 - - name: Install Python 3.9 - uses: actions/setup-python@v3 + - name: Install Python 3.11 + uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Build and check sdist run: | @@ -46,11 +46,11 @@ jobs: platforms: all - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.9.0 + uses: pypa/cibuildwheel@v2.12.0 env: - CIBW_BUILD: 'cp37-* cp38-* cp39-* cp310-* cp311-*' - CIBW_SKIP: "cp37-*-arm64 *-musllinux_*" - # TODO: Build ppc64le using some other trick + CIBW_BUILD: 'cp38-* cp39-* cp310-* cp311-*' + CIBW_SKIP: "*-musllinux_*" + CIBW_TEST_SKIP: "*-macosx_arm64" CIBW_ARCHS_LINUX: x86_64 aarch64 CIBW_ARCHS_MACOS: x86_64 arm64 CIBW_ARCHS_WINDOWS: AMD64 @@ -73,7 +73,7 @@ jobs: name: dist path: dist - - uses: pypa/gh-action-pypi-publish@v1.5.0 + - uses: pypa/gh-action-pypi-publish@v1.6.4 with: user: __token__ password: ${{ secrets.PYPI_PASSWORD }} diff --git a/BUILD.bazel b/BUILD.bazel index 64f86eedc9..99616163e7 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -18,6 +18,12 @@ config_setting( visibility = [":__subpackages__"], ) +config_setting( + name = "macos", + constraint_values = ["@platforms//os:macos"], + visibility = ["//visibility:public"], +) + config_setting( name = "perfcounters", define_values = { diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 03f8ca42f9..8c786fbc28 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -44,13 +44,13 @@ def benchmark_deps(): tag = "release-1.11.0", ) - if "pybind11" not in native.existing_rules(): - http_archive( - name = "pybind11", - build_file = "@//bindings/python:pybind11.BUILD", - sha256 = "eacf582fa8f696227988d08cfc46121770823839fe9e301a20fbce67e7cd70ec", - strip_prefix = "pybind11-2.10.0", - urls = ["https://github.com/pybind/pybind11/archive/v2.10.0.tar.gz"], + if "nanobind" not in native.existing_rules(): + git_repository( + name = "nanobind", + remote = "https://github.com/wjakob/nanobind.git", + commit = "fe3ecb800a7a3e8023e8ee77167a6241591e0b8b", + build_file = "@//bindings/python:nanobind.BUILD", + recursive_init_submodules = True, ) if "libpfm" not in native.existing_rules(): diff --git a/bindings/python/google_benchmark/BUILD b/bindings/python/google_benchmark/BUILD index 3c1561f48e..89ec76e0d5 100644 --- a/bindings/python/google_benchmark/BUILD +++ b/bindings/python/google_benchmark/BUILD @@ -6,7 +6,6 @@ py_library( visibility = ["//visibility:public"], deps = [ ":_benchmark", - # pip; absl:app ], ) @@ -17,10 +16,13 @@ py_extension( "-fexceptions", "-fno-strict-aliasing", ], - features = ["-use_header_modules"], + features = [ + "-use_header_modules", + "-parse_headers", + ], deps = [ "//:benchmark", - "@pybind11", + "@nanobind", "@python_headers", ], ) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index 5614b92817..991da5a5aa 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -2,19 +2,16 @@ #include "benchmark/benchmark.h" -#include -#include -#include +#include "nanobind/nanobind.h" +#include "nanobind/operators.h" +#include "nanobind/stl/bind_map.h" +#include "nanobind/stl/string.h" +#include "nanobind/stl/vector.h" -#include "pybind11/operators.h" -#include "pybind11/pybind11.h" -#include "pybind11/stl.h" -#include "pybind11/stl_bind.h" - -PYBIND11_MAKE_OPAQUE(benchmark::UserCounters); +NB_MAKE_OPAQUE(benchmark::UserCounters); namespace { -namespace py = ::pybind11; +namespace nb = nanobind; std::vector Initialize(const std::vector& argv) { // The `argv` pointers here become invalid when this function returns, but @@ -38,14 +35,15 @@ std::vector Initialize(const std::vector& argv) { } benchmark::internal::Benchmark* RegisterBenchmark(const char* name, - py::function f) { + nb::callable f) { return benchmark::RegisterBenchmark( name, [f](benchmark::State& state) { f(&state); }); } -PYBIND11_MODULE(_benchmark, m) { +NB_MODULE(_benchmark, m) { + using benchmark::TimeUnit; - py::enum_(m, "TimeUnit") + nb::enum_(m, "TimeUnit") .value("kNanosecond", TimeUnit::kNanosecond) .value("kMicrosecond", TimeUnit::kMicrosecond) .value("kMillisecond", TimeUnit::kMillisecond) @@ -53,74 +51,74 @@ PYBIND11_MODULE(_benchmark, m) { .export_values(); using benchmark::BigO; - py::enum_(m, "BigO") + nb::enum_(m, "BigO") .value("oNone", BigO::oNone) .value("o1", BigO::o1) .value("oN", BigO::oN) .value("oNSquared", BigO::oNSquared) .value("oNCubed", BigO::oNCubed) .value("oLogN", BigO::oLogN) - .value("oNLogN", BigO::oLogN) + .value("oNLogN", BigO::oNLogN) .value("oAuto", BigO::oAuto) .value("oLambda", BigO::oLambda) .export_values(); using benchmark::internal::Benchmark; - py::class_(m, "Benchmark") - // For methods returning a pointer tor the current object, reference - // return policy is used to ask pybind not to take ownership oof the + nb::class_(m, "Benchmark") + // For methods returning a pointer to the current object, reference + // return policy is used to ask nanobind not to take ownership of the // returned object and avoid calling delete on it. // https://pybind11.readthedocs.io/en/stable/advanced/functions.html#return-value-policies // // For methods taking a const std::vector<...>&, a copy is created // because a it is bound to a Python list. // https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html - .def("unit", &Benchmark::Unit, py::return_value_policy::reference) - .def("arg", &Benchmark::Arg, py::return_value_policy::reference) - .def("args", &Benchmark::Args, py::return_value_policy::reference) - .def("range", &Benchmark::Range, py::return_value_policy::reference, - py::arg("start"), py::arg("limit")) + .def("unit", &Benchmark::Unit, nb::rv_policy::reference) + .def("arg", &Benchmark::Arg, nb::rv_policy::reference) + .def("args", &Benchmark::Args, nb::rv_policy::reference) + .def("range", &Benchmark::Range, nb::rv_policy::reference, + nb::arg("start"), nb::arg("limit")) .def("dense_range", &Benchmark::DenseRange, - py::return_value_policy::reference, py::arg("start"), - py::arg("limit"), py::arg("step") = 1) - .def("ranges", &Benchmark::Ranges, py::return_value_policy::reference) + nb::rv_policy::reference, nb::arg("start"), + nb::arg("limit"), nb::arg("step") = 1) + .def("ranges", &Benchmark::Ranges, nb::rv_policy::reference) .def("args_product", &Benchmark::ArgsProduct, - py::return_value_policy::reference) - .def("arg_name", &Benchmark::ArgName, py::return_value_policy::reference) + nb::rv_policy::reference) + .def("arg_name", &Benchmark::ArgName, nb::rv_policy::reference) .def("arg_names", &Benchmark::ArgNames, - py::return_value_policy::reference) + nb::rv_policy::reference) .def("range_pair", &Benchmark::RangePair, - py::return_value_policy::reference, py::arg("lo1"), py::arg("hi1"), - py::arg("lo2"), py::arg("hi2")) + nb::rv_policy::reference, nb::arg("lo1"), nb::arg("hi1"), + nb::arg("lo2"), nb::arg("hi2")) .def("range_multiplier", &Benchmark::RangeMultiplier, - py::return_value_policy::reference) - .def("min_time", &Benchmark::MinTime, py::return_value_policy::reference) + nb::rv_policy::reference) + .def("min_time", &Benchmark::MinTime, nb::rv_policy::reference) .def("min_warmup_time", &Benchmark::MinWarmUpTime, - py::return_value_policy::reference) + nb::rv_policy::reference) .def("iterations", &Benchmark::Iterations, - py::return_value_policy::reference) + nb::rv_policy::reference) .def("repetitions", &Benchmark::Repetitions, - py::return_value_policy::reference) + nb::rv_policy::reference) .def("report_aggregates_only", &Benchmark::ReportAggregatesOnly, - py::return_value_policy::reference, py::arg("value") = true) + nb::rv_policy::reference, nb::arg("value") = true) .def("display_aggregates_only", &Benchmark::DisplayAggregatesOnly, - py::return_value_policy::reference, py::arg("value") = true) + nb::rv_policy::reference, nb::arg("value") = true) .def("measure_process_cpu_time", &Benchmark::MeasureProcessCPUTime, - py::return_value_policy::reference) + nb::rv_policy::reference) .def("use_real_time", &Benchmark::UseRealTime, - py::return_value_policy::reference) + nb::rv_policy::reference) .def("use_manual_time", &Benchmark::UseManualTime, - py::return_value_policy::reference) + nb::rv_policy::reference) .def( "complexity", (Benchmark * (Benchmark::*)(benchmark::BigO)) & Benchmark::Complexity, - py::return_value_policy::reference, - py::arg("complexity") = benchmark::oAuto); + nb::rv_policy::reference, + nb::arg("complexity") = benchmark::oAuto); using benchmark::Counter; - py::class_ py_counter(m, "Counter"); + nb::class_ py_counter(m, "Counter"); - py::enum_(py_counter, "Flags") + nb::enum_(py_counter, "Flags") .value("kDefaults", Counter::Flags::kDefaults) .value("kIsRate", Counter::Flags::kIsRate) .value("kAvgThreads", Counter::Flags::kAvgThreads) @@ -132,28 +130,29 @@ PYBIND11_MODULE(_benchmark, m) { .value("kAvgIterationsRate", Counter::Flags::kAvgIterationsRate) .value("kInvert", Counter::Flags::kInvert) .export_values() - .def(py::self | py::self); + .def(nb::self | nb::self); - py::enum_(py_counter, "OneK") + nb::enum_(py_counter, "OneK") .value("kIs1000", Counter::OneK::kIs1000) .value("kIs1024", Counter::OneK::kIs1024) .export_values(); py_counter - .def(py::init(), - py::arg("value") = 0., py::arg("flags") = Counter::kDefaults, - py::arg("k") = Counter::kIs1000) - .def(py::init([](double value) { return Counter(value); })) + .def(nb::init(), + nb::arg("value") = 0., nb::arg("flags") = Counter::kDefaults, + nb::arg("k") = Counter::kIs1000) + .def("__init__", ([](Counter *c, double value) { new (c) Counter(value); })) .def_readwrite("value", &Counter::value) .def_readwrite("flags", &Counter::flags) - .def_readwrite("oneK", &Counter::oneK); - py::implicitly_convertible(); - py::implicitly_convertible(); + .def_readwrite("oneK", &Counter::oneK) + .def(nb::init_implicit()); + + nb::implicitly_convertible(); - py::bind_map(m, "UserCounters"); + nb::bind_map(m, "UserCounters"); using benchmark::State; - py::class_(m, "State") + nb::class_(m, "State") .def("__bool__", &State::KeepRunning) .def_property_readonly("keep_running", &State::KeepRunning) .def("pause_timing", &State::PauseTiming) @@ -168,15 +167,16 @@ PYBIND11_MODULE(_benchmark, m) { .def_property("items_processed", &State::items_processed, &State::SetItemsProcessed) .def("set_label", (void (State::*)(const char*)) & State::SetLabel) - .def("range", &State::range, py::arg("pos") = 0) + .def("range", &State::range, nb::arg("pos") = 0) .def_property_readonly("iterations", &State::iterations) + .def_property_readonly("name", &State::name) .def_readwrite("counters", &State::counters) .def_property_readonly("thread_index", &State::thread_index) .def_property_readonly("threads", &State::threads); m.def("Initialize", Initialize); m.def("RegisterBenchmark", RegisterBenchmark, - py::return_value_policy::reference); + nb::rv_policy::reference); m.def("RunSpecifiedBenchmarks", []() { benchmark::RunSpecifiedBenchmarks(); }); m.def("ClearRegisteredBenchmarks", benchmark::ClearRegisteredBenchmarks); diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD new file mode 100644 index 0000000000..9a8d6a041b --- /dev/null +++ b/bindings/python/nanobind.BUILD @@ -0,0 +1,52 @@ + +config_setting( + name = "msvc_compiler", + flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"}, +) + +cc_library( + name = "nanobind", + hdrs = glob( + include = [ + "include/nanobind/*.h", + "include/nanobind/stl/*.h", + "include/nanobind/detail/*.h", + ], + exclude = [], + ), + srcs = [ + "include/nanobind/stl/detail/nb_dict.h", + "include/nanobind/stl/detail/nb_list.h", + "include/nanobind/stl/detail/traits.h", + "ext/robin_map/include/tsl/robin_map.h", + "ext/robin_map/include/tsl/robin_hash.h", + "ext/robin_map/include/tsl/robin_growth_policy.h", + "ext/robin_map/include/tsl/robin_set.h", + "src/buffer.h", + "src/common.cpp", + "src/error.cpp", + "src/implicit.cpp", + "src/nb_enum.cpp", + "src/nb_func.cpp", + "src/nb_internals.cpp", + "src/nb_internals.h", + "src/nb_type.cpp", + "src/tensor.cpp", + "src/trampoline.cpp", + ], + copts = select({ + ":msvc_compiler": [], + "//conditions:default": [ + "-fexceptions", + "-Os", # size optimization + "-flto", # enable LTO + ], + }), + linkopts = select({ + "@com_github_google_benchmark//:macos": ["-undefined suppress", "-flat_namespace"], + "//conditions:default": [], + }), + includes = ["include", "ext/robin_map/include"], + deps = ["@python_headers"], + visibility = ["//visibility:public"], +) diff --git a/bindings/python/pybind11.BUILD b/bindings/python/pybind11.BUILD deleted file mode 100644 index bc83350038..0000000000 --- a/bindings/python/pybind11.BUILD +++ /dev/null @@ -1,20 +0,0 @@ -cc_library( - name = "pybind11", - hdrs = glob( - include = [ - "include/pybind11/*.h", - "include/pybind11/detail/*.h", - ], - exclude = [ - "include/pybind11/common.h", - "include/pybind11/eigen.h", - ], - ), - copts = [ - "-fexceptions", - "-Wno-undefined-inline", - "-Wno-pragma-once-outside-header", - ], - includes = ["include"], - visibility = ["//visibility:public"], -) diff --git a/setup.py b/setup.py index 0f48636237..2388f59b9b 100644 --- a/setup.py +++ b/setup.py @@ -88,23 +88,31 @@ def bazel_build(self, ext: BazelExtension): bazel_argv = [ "bazel", "build", - str(ext.bazel_target), + ext.bazel_target, f"--symlink_prefix={temp_path / 'bazel-'}", f"--compilation_mode={'dbg' if self.debug else 'opt'}", + # C++17 is required by nanobind + f"--cxxopt={'/std:c++17' if IS_WINDOWS else '-std=c++17'}", ] if IS_WINDOWS: # Link with python*.lib. for library_dir in self.library_dirs: bazel_argv.append("--linkopt=/LIBPATH:" + library_dir) - elif IS_MAC and platform.machine() == "x86_64": - bazel_argv.append("--macos_minimum_os=10.9") + elif IS_MAC: + if platform.machine() == "x86_64": + # C++17 needs macOS 10.14 at minimum + bazel_argv.append("--macos_minimum_os=10.14") - # ARCHFLAGS is always set by cibuildwheel before macOS wheel builds. - archflags = os.getenv("ARCHFLAGS", "") - if "arm64" in archflags: - bazel_argv.append("--cpu=darwin_arm64") - bazel_argv.append("--macos_cpus=arm64") + # cross-compilation for Mac ARM64 on GitHub Mac x86 runners. + # ARCHFLAGS is set by cibuildwheel before macOS wheel builds. + archflags = os.getenv("ARCHFLAGS", "") + if "arm64" in archflags: + bazel_argv.append("--cpu=darwin_arm64") + bazel_argv.append("--macos_cpus=arm64") + + elif platform.machine() == "arm64": + bazel_argv.append("--macos_minimum_os=11.0") self.spawn(bazel_argv) @@ -146,7 +154,6 @@ def bazel_build(self, ext: BazelExtension): "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", From 1318865305834c402f61c0b9d5ad06b6900f1de7 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 6 Feb 2023 15:01:16 +0100 Subject: [PATCH 058/561] try disabling liquid for jekyll to fix curly braces (#1536) * try disabling liquid for jekyll to fix curly braces * do it properly with commented out tags --- docs/AssemblyTests.md | 2 ++ docs/_config.yml | 2 +- docs/user_guide.md | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/AssemblyTests.md b/docs/AssemblyTests.md index 1fbdc269b5..89df7ca520 100644 --- a/docs/AssemblyTests.md +++ b/docs/AssemblyTests.md @@ -111,6 +111,7 @@ between compilers or compiler versions. A common example of this is matching stack frame addresses. In this case regular expressions can be used to match the differing bits of output. For example: + ```c++ int ExternInt; struct Point { int x, y, z; }; @@ -127,6 +128,7 @@ extern "C" void test_store_point() { // CHECK: ret } ``` + ## Current Requirements and Limitations diff --git a/docs/_config.yml b/docs/_config.yml index 2f7efbeab5..fff4ab923c 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-minimal \ No newline at end of file +theme: jekyll-theme-minimal diff --git a/docs/user_guide.md b/docs/user_guide.md index 3c2e8f7edc..fbd29b9aae 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -386,14 +386,17 @@ short-hand. The following macro will pick a few appropriate arguments in the product of the two specified ranges and will generate a benchmark for each such pair. + ```c++ BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}}); ``` + Some benchmarks may require specific argument values that cannot be expressed with `Ranges`. In this case, `ArgsProduct` offers the ability to generate a benchmark input for each combination in the product of the supplied vectors. + ```c++ BENCHMARK(BM_SetInsert) ->ArgsProduct({{1<<10, 3<<10, 8<<10}, {20, 40, 60, 80}}) @@ -412,6 +415,7 @@ BENCHMARK(BM_SetInsert) ->Args({3<<10, 80}) ->Args({8<<10, 80}); ``` + For the most common scenarios, helper methods for creating a list of integers for a given sparse or dense range are provided. @@ -697,6 +701,7 @@ is 1k a 1000 (default, `benchmark::Counter::OneK::kIs1000`), or 1024 When you're compiling in C++11 mode or later you can use `insert()` with `std::initializer_list`: + ```c++ // With C++11, this can be done: state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}}); @@ -705,6 +710,7 @@ When you're compiling in C++11 mode or later you can use `insert()` with state.counters["Bar"] = numBars; state.counters["Baz"] = numBazs; ``` + ### Counter Reporting @@ -873,6 +879,7 @@ is measured. But sometimes, it is necessary to do some work inside of that loop, every iteration, but without counting that time to the benchmark time. That is possible, although it is not recommended, since it has high overhead. + ```c++ static void BM_SetInsert_With_Timer_Control(benchmark::State& state) { std::set data; @@ -887,6 +894,7 @@ static void BM_SetInsert_With_Timer_Control(benchmark::State& state) { } BENCHMARK(BM_SetInsert_With_Timer_Control)->Ranges({{1<<10, 8<<10}, {128, 512}}); ``` + From 94083ca441323fb68f8cbd9fd163a26eead158c2 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 6 Feb 2023 16:37:26 +0100 Subject: [PATCH 059/561] remove best effort support for ubuntu 18.04 (#1537) * remove deprecated ubuntu-18.04 target * update docs * force an apt update for perfcounters --- .github/workflows/build-and-test-perfcounters.yml | 13 ++++--------- .github/workflows/build-and-test.yml | 9 +-------- docs/dependencies.md | 3 --- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index e162edcbef..b6096c2b54 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -14,20 +14,15 @@ jobs: strategy: fail-fast: false matrix: - # ubuntu-18.04 is deprecated but included for best-effort - os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04] + os: [ubuntu-22.04, ubuntu-20.04] build_type: ['Release', 'Debug'] steps: - uses: actions/checkout@v2 - name: install libpfm - run: sudo apt -y install libpfm4-dev - - - name: setup cmake - if: matrix.os == 'ubuntu-18.04' - uses: jwlawson/actions-setup-cmake@v1.9 - with: - cmake-version: '3.16.3' + run: | + sudo apt update + sudo apt -y install libpfm4-dev - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2441e26b60..764192f5a7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,8 +17,7 @@ jobs: strategy: fail-fast: false matrix: - # ubuntu-18.04 is deprecated but included for best-effort support - os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04, macos-latest] + os: [ubuntu-22.04, ubuntu-20.04, macos-latest] build_type: ['Release', 'Debug'] compiler: [g++, clang++] lib: ['shared', 'static'] @@ -26,12 +25,6 @@ jobs: steps: - uses: actions/checkout@v2 - - name: setup cmake - if: matrix.os == 'ubuntu-18.04' - uses: jwlawson/actions-setup-cmake@v1.9 - with: - cmake-version: '3.16.3' - - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build diff --git a/docs/dependencies.md b/docs/dependencies.md index 57003aa334..98aae42af6 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -9,12 +9,9 @@ still allow forward progress, we require any build tooling to be available for: Currently, this means using build tool versions that are available for Ubuntu Ubuntu 20.04 (Focal Fossa), Ubuntu 22.04 (Jammy Jellyfish) and Debian 11.4 (bullseye). -_Note, CI also runs ubuntu-18.04 to attempt best effort support for older versions._ - ## cmake The current supported version is cmake 3.16.3 as of 2022-08-10. -* _3.10.2 (ubuntu 18.04)_ * 3.16.3 (ubuntu 20.04) * 3.18.4 (debian 11.4) * 3.22.1 (ubuntu 22.04) From 53df805dc820d720734d6538032f6b73f31f13ba Mon Sep 17 00:00:00 2001 From: Chris Kennelly Date: Mon, 6 Feb 2023 10:50:37 -0500 Subject: [PATCH 060/561] Deprecate constant reference API to DoNotOptimize. (#1493) The compiler assume that a constant reference, even though escaped via asm volatile, is unchanged. The const-ref interface is deprecated to discourage new uses of it, as subtle compiler optimizations (invariant hoisting, etc.) can occur. Within microbenchmarks for Abseil's hashtables, BM_FindMiss_Hot (https://github.com/google/fleetbench/blob/c0eaa90671d6cc99eb065864e74f0175bee24a5d/fleetbench/swissmap/hot_swissmap_benchmark.cc#L48) has a `const uint32_t key` is passed to to the lookup of a hashtable. With the `key` marked `const`, LLVM hoists part of the lookup calculation outside of the loop. With the `const` removed, this hoisting does not occur. Co-authored-by: Dominic Hamon Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- include/benchmark/benchmark.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index e8b1a7d6d4..b44cfc1636 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -435,6 +435,9 @@ inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { #ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY #if !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { asm volatile("" : : "r,m"(value) : "memory"); } @@ -451,6 +454,9 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { // Workaround for a bug with full argument copy overhead with GCC. // See: #1340 and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105519 template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value && (sizeof(Tp) <= sizeof(Tp*))>::type @@ -459,6 +465,9 @@ inline BENCHMARK_ALWAYS_INLINE } template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value || (sizeof(Tp) > sizeof(Tp*))>::type @@ -487,6 +496,9 @@ inline BENCHMARK_ALWAYS_INLINE // to use memory operations instead of operations with registers. // TODO: Remove if GCC < 5 will be unsupported. template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { asm volatile("" : : "m"(value) : "memory"); } @@ -504,6 +516,9 @@ inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { #endif #elif defined(_MSC_VER) template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { internal::UseCharPointer(&reinterpret_cast(value)); _ReadWriteBarrier(); @@ -514,6 +529,9 @@ inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { _ReadWriteBarrier(); } #endif #else template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { internal::UseCharPointer(&reinterpret_cast(value)); } From 4c9cee34f20071a8d08e202afe679e4269f161e2 Mon Sep 17 00:00:00 2001 From: JbR <90027771+jbr-smtg@users.noreply.github.com> Date: Mon, 6 Feb 2023 16:58:14 +0100 Subject: [PATCH 061/561] Fixing issue with ARM64EC and MSVC (#1514) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/cycleclock.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index df6ffa51ae..ae1ef2d2d2 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -36,7 +36,8 @@ // declarations of some other intrinsics, breaking compilation. // Therefore, we simply declare __rdtsc ourselves. See also // http://connect.microsoft.com/VisualStudio/feedback/details/262047 -#if defined(COMPILER_MSVC) && !defined(_M_IX86) && !defined(_M_ARM64) +#if defined(COMPILER_MSVC) && !defined(_M_IX86) && !defined(_M_ARM64) && \ + !defined(_M_ARM64EC) extern "C" uint64_t __rdtsc(); #pragma intrinsic(__rdtsc) #endif @@ -114,7 +115,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { // when I know it will work. Otherwise, I'll use __rdtsc and hope // the code is being compiled with a non-ancient compiler. _asm rdtsc -#elif defined(COMPILER_MSVC) && defined(_M_ARM64) +#elif defined(COMPILER_MSVC) && (defined(_M_ARM64) || defined(_M_ARM64EC)) // See // https://docs.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics // and https://reviews.llvm.org/D53115 int64_t virtual_timer_value; From ff8d44c9282d23233ec8932585b0c3ae6557263f Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 6 Feb 2023 17:34:47 +0100 Subject: [PATCH 062/561] fix #1446 by removing the address operator (#1538) * fix #1446 by removing the address operator * add test * format --------- Co-authored-by: Thomas Co-authored-by: Dominic Hamon --- include/benchmark/benchmark.h | 2 +- test/benchmark_test.cc | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index b44cfc1636..ba997e8c67 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1379,7 +1379,7 @@ class Fixture : public internal::Benchmark { BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ new ::benchmark::internal::FunctionBenchmark(#__VA_ARGS__, \ - &__VA_ARGS__))) + __VA_ARGS__))) #else #define BENCHMARK(n) \ BENCHMARK_PRIVATE_DECLARE(n) = \ diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index bd6005d194..ce233ece2c 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -254,4 +255,16 @@ static void BM_BenchmarkName(benchmark::State& state) { } BENCHMARK(BM_BenchmarkName); +// regression test for #1446 +template +static void BM_templated_test(benchmark::State& state) { + for (auto _ : state) { + type created_string; + benchmark::DoNotOptimize(created_string); + } +} + +static auto BM_templated_test_double = BM_templated_test>; +BENCHMARK(BM_templated_test_double); + BENCHMARK_MAIN(); From f15f332fd1ae10ae6d13d816af9bcf3b196974cc Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 6 Feb 2023 16:38:53 +0000 Subject: [PATCH 063/561] get rid of some deprecation warnings from tests --- test/benchmark_test.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index ce233ece2c..94590d5e41 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -75,7 +75,8 @@ BENCHMARK_RANGE(BM_CalculatePiRange, 1, 1024 * 1024); static void BM_CalculatePi(benchmark::State& state) { static const int depth = 1024; for (auto _ : state) { - benchmark::DoNotOptimize(CalculatePi(static_cast(depth))); + double pi = CalculatePi(static_cast(depth)); + benchmark::DoNotOptimize(pi); } } BENCHMARK(BM_CalculatePi)->Threads(8); @@ -124,7 +125,10 @@ static void BM_StringCompare(benchmark::State& state) { size_t len = static_cast(state.range(0)); std::string s1(len, '-'); std::string s2(len, '-'); - for (auto _ : state) benchmark::DoNotOptimize(s1.compare(s2)); + for (auto _ : state) { + auto comp = s1.compare(s2); + benchmark::DoNotOptimize(comp); + } } BENCHMARK(BM_StringCompare)->Range(1, 1 << 20); From 6bc17754f60e3cdadc1921fa167ca1fb877c4159 Mon Sep 17 00:00:00 2001 From: Matt Armstrong Date: Mon, 6 Feb 2023 08:57:07 -0800 Subject: [PATCH 064/561] Support --benchmarks_filter in the compare.py 'benchmarks' command (#1486) Previously compare.py ignored the --benchmarks_filter argument when loading JSON. This defeated any workflow when a single run of the benchmark was run, followed by multiple "subset reports" run against it with the 'benchmarks' command. Concretely this came up with the simple case: compare.py benchmarks a.json b.json --benchmarks_filter=BM_Example This has no practical impact on the 'filters' and 'benchmarkfiltered' comand, which do their thing at a later stage. Fixes #1484 Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/compare.py | 21 ++++++++++++--------- tools/gbench/util.py | 34 ++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/tools/compare.py b/tools/compare.py index 8cefdd17c1..e5eeb247e6 100755 --- a/tools/compare.py +++ b/tools/compare.py @@ -9,25 +9,28 @@ from argparse import ArgumentParser import json import sys +import os import gbench from gbench import util, report -from gbench.util import * def check_inputs(in1, in2, flags): """ Perform checking on the user provided inputs and diagnose any abnormalities """ - in1_kind, in1_err = classify_input_file(in1) - in2_kind, in2_err = classify_input_file(in2) - output_file = find_benchmark_flag('--benchmark_out=', flags) - output_type = find_benchmark_flag('--benchmark_out_format=', flags) - if in1_kind == IT_Executable and in2_kind == IT_Executable and output_file: + in1_kind, in1_err = util.classify_input_file(in1) + in2_kind, in2_err = util.classify_input_file(in2) + output_file = util.find_benchmark_flag('--benchmark_out=', flags) + output_type = util.find_benchmark_flag('--benchmark_out_format=', flags) + if in1_kind == util.IT_Executable and in2_kind == util.IT_Executable and output_file: print(("WARNING: '--benchmark_out=%s' will be passed to both " "benchmarks causing it to be overwritten") % output_file) - if in1_kind == IT_JSON and in2_kind == IT_JSON and len(flags) > 0: - print("WARNING: passing optional flags has no effect since both " - "inputs are JSON") + if in1_kind == util.IT_JSON and in2_kind == util.IT_JSON: + # When both sides are JSON the only supported flag is + # --benchmark_filter= + for flag in util.remove_benchmark_flags('--benchmark_filter=', flags): + print("WARNING: passing %s has no effect since both " + "inputs are JSON" % flag) if output_type is not None and output_type != 'json': print(("ERROR: passing '--benchmark_out_format=%s' to 'compare.py`" " is not supported.") % output_type) diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 95d7994b3e..5e79da8f01 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -2,10 +2,11 @@ """ import json import os -import tempfile +import re import subprocess import sys -import functools +import tempfile + # Input file type enumeration IT_Invalid = 0 @@ -111,13 +112,32 @@ def remove_benchmark_flags(prefix, benchmark_flags): return [f for f in benchmark_flags if not f.startswith(prefix)] -def load_benchmark_results(fname): +def load_benchmark_results(fname, benchmark_filter): """ Read benchmark output from a file and return the JSON object. + + Apply benchmark_filter, a regular expression, with nearly the same + semantics of the --benchmark_filter argument. May be None. + Note: the Python regular expression engine is used instead of the + one used by the C++ code, which may produce different results + in complex cases. + REQUIRES: 'fname' names a file containing JSON benchmark output. """ + def benchmark_wanted(benchmark): + if benchmark_filter is None: + return True + name = benchmark.get('run_name', None) or benchmark['name'] + if re.search(benchmark_filter, name): + return True + return False + with open(fname, 'r') as f: - return json.load(f) + results = json.load(f) + if 'benchmarks' in results: + results['benchmarks'] = list(filter(benchmark_wanted, + results['benchmarks'])) + return results def sort_benchmark_results(result): @@ -160,7 +180,7 @@ def run_benchmark(exe_name, benchmark_flags): if exitCode != 0: print('TEST FAILED...') sys.exit(exitCode) - json_res = load_benchmark_results(output_name) + json_res = load_benchmark_results(output_name, None) if is_temp_output: os.unlink(output_name) return json_res @@ -175,7 +195,9 @@ def run_or_load_benchmark(filename, benchmark_flags): """ ftype = check_input_file(filename) if ftype == IT_JSON: - return load_benchmark_results(filename) + benchmark_filter = find_benchmark_flag('--benchmark_filter=', + benchmark_flags) + return load_benchmark_results(filename, benchmark_filter) if ftype == IT_Executable: return run_benchmark(filename, benchmark_flags) raise ValueError('Unknown file type %s' % ftype) From 6cf7725ea1339cd39b4a066bebee1203162aa933 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 7 Feb 2023 06:45:18 -0500 Subject: [PATCH 065/561] Allow specifying number of iterations via --benchmark_min_time. (#1525) * Allow specifying number of iterations via --benchmark_min_time. Make the flag accept two new suffixes: + x: number of iterations + s: minimum number of seconds. This matches the internal benchmark API. * forgot to change flag type to string * used tagged union instead of std::variant, which is not available pre C++14 * update decl in benchmark_runner.h too * fixed errors * refactor * backward compat * typo * use IterationCount type * fixed test * const_cast * ret type * remove extra _ * debug * fixed bug from reporting that caused the new configs not to be included in the final report * addressed review comments * restore unnecessary changes in test/BUILD * fix float comparisons warnings from Release builds * clang format * fix visibility warning * remove misc file * removed backup files * addressed review comments * fix shorten in warning * use suffix for existing min_time specs to silent warnings in tests * fix leaks * use default min-time value in flag decl for consistency * removed double kMinTimeDecl from benchmark.h * dont need to preserve errno * add death tests * Add BENCHMARK_EXPORT to hopefully fix missing def errors * only enable death tests in debug mode because bm_check is no-op in release mode * guard death tests with additional support-check macros * Add additional guard to prevent running in Release mode --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- include/benchmark/benchmark.h | 12 ++- src/benchmark.cc | 25 ++++-- src/benchmark_runner.cc | 88 ++++++++++++++++++++- src/benchmark_runner.h | 20 ++++- test/BUILD | 22 +++--- test/CMakeLists.txt | 61 ++++++++------- test/benchmark_min_time_flag_iters_test.cc | 64 +++++++++++++++ test/benchmark_min_time_flag_time_test.cc | 90 ++++++++++++++++++++++ test/min_time_parse_gtest.cc | 30 ++++++++ 9 files changed, 364 insertions(+), 48 deletions(-) create mode 100644 test/benchmark_min_time_flag_iters_test.cc create mode 100644 test/benchmark_min_time_flag_time_test.cc create mode 100644 test/min_time_parse_gtest.cc diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index ba997e8c67..c154a15782 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -280,6 +280,9 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); namespace benchmark { class BenchmarkReporter; +// Default number of minimum benchmark running time in seconds. +const char kDefaultMinTimeStr[] = "0.5s"; + BENCHMARK_EXPORT void PrintDefaultHelp(); BENCHMARK_EXPORT void Initialize(int* argc, char** argv, @@ -1099,11 +1102,12 @@ class BENCHMARK_EXPORT Benchmark { Benchmark* MinWarmUpTime(double t); // Specify the amount of iterations that should be run by this benchmark. + // This option overrides the `benchmark_min_time` flag. // REQUIRES: 'n > 0' and `MinTime` has not been called on this benchmark. // // NOTE: This function should only be used when *exact* iteration control is // needed and never to control or limit how long a benchmark runs, where - // `--benchmark_min_time=N` or `MinTime(...)` should be used instead. + // `--benchmark_min_time=s` or `MinTime(...)` should be used instead. Benchmark* Iterations(IterationCount n); // Specify the amount of times to repeat this benchmark. This option overrides @@ -1739,6 +1743,12 @@ class BENCHMARK_EXPORT BenchmarkReporter { // to skip runs based on the context information. virtual bool ReportContext(const Context& context) = 0; + // Called once for each group of benchmark runs, gives information about + // the configurations of the runs. + virtual void ReportRunsConfig(double /*min_time*/, + bool /*has_explicit_iters*/, + IterationCount /*iters*/) {} + // Called once for each group of benchmark runs, gives information about // cpu-time and heap memory usage during the benchmark run. If the group // of runs contained more than two entries then 'report' contains additional diff --git a/src/benchmark.cc b/src/benchmark.cc index 8e7408f8fa..e2d85fe494 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -65,12 +65,21 @@ BM_DEFINE_bool(benchmark_list_tests, false); // linked into the binary are run. BM_DEFINE_string(benchmark_filter, ""); -// Minimum number of seconds we should run benchmark before results are -// considered significant. For cpu-time based tests, this is the lower bound +// Specification of how long to run the benchmark. +// +// It can be either an exact number of iterations (specified as `x`), +// or a minimum number of seconds (specified as `s`). If the latter +// format (ie., min seconds) is used, the system may run the benchmark longer +// until the results are considered significant. +// +// For backward compatibility, the `s` suffix may be omitted, in which case, +// the specified number is interpreted as the number of seconds. +// +// For cpu-time based tests, this is the lower bound // on the total cpu time used by all threads that make up the test. For // real-time based tests, this is the lower bound on the elapsed time of the // benchmark execution, regardless of number of threads. -BM_DEFINE_double(benchmark_min_time, 0.5); +BM_DEFINE_string(benchmark_min_time, kDefaultMinTimeStr); // Minimum number of seconds a benchmark should be run before results should be // taken into account. This e.g can be necessary for benchmarks of code which @@ -377,6 +386,12 @@ void RunBenchmarks(const std::vector& benchmarks, if (runner.HasRepeatsRemaining()) continue; // FIXME: report each repetition separately, not all of them in bulk. + display_reporter->ReportRunsConfig( + runner.GetMinTime(), runner.HasExplicitIters(), runner.GetIters()); + if (file_reporter) + file_reporter->ReportRunsConfig( + runner.GetMinTime(), runner.HasExplicitIters(), runner.GetIters()); + RunResults run_results = runner.GetResults(); // Maybe calculate complexity report @@ -610,7 +625,7 @@ void ParseCommandLineFlags(int* argc, char** argv) { if (ParseBoolFlag(argv[i], "benchmark_list_tests", &FLAGS_benchmark_list_tests) || ParseStringFlag(argv[i], "benchmark_filter", &FLAGS_benchmark_filter) || - ParseDoubleFlag(argv[i], "benchmark_min_time", + ParseStringFlag(argv[i], "benchmark_min_time", &FLAGS_benchmark_min_time) || ParseDoubleFlag(argv[i], "benchmark_min_warmup_time", &FLAGS_benchmark_min_warmup_time) || @@ -671,7 +686,7 @@ void PrintDefaultHelp() { "benchmark" " [--benchmark_list_tests={true|false}]\n" " [--benchmark_filter=]\n" - " [--benchmark_min_time=]\n" + " [--benchmark_min_time=`x` OR `s` ]\n" " [--benchmark_min_warmup_time=]\n" " [--benchmark_repetitions=]\n" " [--benchmark_enable_random_interleaving={true|false}]\n" diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 04e5c2a758..eb0d9cbe79 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -28,11 +28,14 @@ #include #include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -62,6 +65,8 @@ MemoryManager* memory_manager = nullptr; namespace { static constexpr IterationCount kMaxIterations = 1000000000; +const double kDefaultMinTime = + std::strtod(::benchmark::kDefaultMinTimeStr, /*p_end*/ nullptr); BenchmarkReporter::Run CreateRunReport( const benchmark::internal::BenchmarkInstance& b, @@ -140,23 +145,100 @@ void RunInThread(const BenchmarkInstance* b, IterationCount iters, manager->NotifyThreadComplete(); } +double ComputeMinTime(const benchmark::internal::BenchmarkInstance& b, + const BenchTimeType& iters_or_time) { + if (!IsZero(b.min_time())) return b.min_time(); + // If the flag was used to specify number of iters, then return the default + // min_time. + if (iters_or_time.tag == BenchTimeType::ITERS) return kDefaultMinTime; + + return iters_or_time.time; +} + +IterationCount ComputeIters(const benchmark::internal::BenchmarkInstance& b, + const BenchTimeType& iters_or_time) { + if (b.iterations() != 0) return b.iterations(); + + // We've already concluded that this flag is currently used to pass + // iters but do a check here again anyway. + BM_CHECK(iters_or_time.tag == BenchTimeType::ITERS); + return iters_or_time.iters; +} + } // end namespace +BenchTimeType ParseBenchMinTime(const std::string& value) { + BenchTimeType ret; + + if (value.empty()) { + ret.tag = BenchTimeType::TIME; + ret.time = 0.0; + return ret; + } + + if (value.back() == 'x') { + const char* iters_str = value.c_str(); + char* p_end; + // Reset errno before it's changed by strtol. + errno = 0; + IterationCount num_iters = std::strtol(iters_str, &p_end, 10); + + // After a valid parse, p_end should have been set to + // point to the 'x' suffix. + BM_CHECK(errno == 0 && p_end != nullptr && *p_end == 'x') + << "Malformed iters value passed to --benchmark_min_time: `" << value + << "`. Expected --benchmark_min_time=x."; + + ret.tag = BenchTimeType::ITERS; + ret.iters = num_iters; + return ret; + } + + const char* time_str = value.c_str(); + bool has_suffix = value.back() == 's'; + if (!has_suffix) { + BM_VLOG(0) << "Value passed to --benchmark_min_time should have a suffix. " + "Eg., `30s` for 30-seconds."; + } + + char* p_end; + // Reset errno before it's changed by strtod. + errno = 0; + double min_time = std::strtod(time_str, &p_end); + + // After a successfull parse, p_end should point to the suffix 's' + // or the end of the string, if the suffix was omitted. + BM_CHECK(errno == 0 && p_end != nullptr && + (has_suffix && *p_end == 's' || *p_end == '\0')) + << "Malformed seconds value passed to --benchmark_min_time: `" << value + << "`. Expected --benchmark_min_time=x."; + + ret.tag = BenchTimeType::TIME; + ret.time = min_time; + + return ret; +} + BenchmarkRunner::BenchmarkRunner( const benchmark::internal::BenchmarkInstance& b_, BenchmarkReporter::PerFamilyRunReports* reports_for_family_) : b(b_), reports_for_family(reports_for_family_), - min_time(!IsZero(b.min_time()) ? b.min_time() : FLAGS_benchmark_min_time), + parsed_benchtime_flag(ParseBenchMinTime(FLAGS_benchmark_min_time)), + min_time(ComputeMinTime(b_, parsed_benchtime_flag)), min_warmup_time((!IsZero(b.min_time()) && b.min_warmup_time() > 0.0) ? b.min_warmup_time() : FLAGS_benchmark_min_warmup_time), warmup_done(!(min_warmup_time > 0.0)), repeats(b.repetitions() != 0 ? b.repetitions() : FLAGS_benchmark_repetitions), - has_explicit_iteration_count(b.iterations() != 0), + has_explicit_iteration_count(b.iterations() != 0 || + parsed_benchtime_flag.tag == + BenchTimeType::ITERS), pool(b.threads() - 1), - iters(has_explicit_iteration_count ? b.iterations() : 1), + iters(has_explicit_iteration_count + ? ComputeIters(b_, parsed_benchtime_flag) + : 1), perf_counters_measurement(StrSplit(FLAGS_benchmark_perf_counters, ',')), perf_counters_measurement_ptr(perf_counters_measurement.IsValid() ? &perf_counters_measurement diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index 0174bd3401..9d80653728 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -25,7 +25,7 @@ namespace benchmark { -BM_DECLARE_double(benchmark_min_time); +BM_DECLARE_string(benchmark_min_time); BM_DECLARE_double(benchmark_min_warmup_time); BM_DECLARE_int32(benchmark_repetitions); BM_DECLARE_bool(benchmark_report_aggregates_only); @@ -44,6 +44,17 @@ struct RunResults { bool file_report_aggregates_only = false; }; +struct BENCHMARK_EXPORT BenchTimeType { + enum { ITERS, TIME } tag; + union { + IterationCount iters; + double time; + }; +}; + +BENCHMARK_EXPORT +BenchTimeType ParseBenchMinTime(const std::string& value); + class BenchmarkRunner { public: BenchmarkRunner(const benchmark::internal::BenchmarkInstance& b_, @@ -63,12 +74,19 @@ class BenchmarkRunner { return reports_for_family; } + double GetMinTime() const { return min_time; } + + bool HasExplicitIters() const { return has_explicit_iteration_count; } + + IterationCount GetIters() const { return iters; } + private: RunResults run_results; const benchmark::internal::BenchmarkInstance& b; BenchmarkReporter::PerFamilyRunReports* reports_for_family; + BenchTimeType parsed_benchtime_flag; const double min_time; const double min_warmup_time; bool warmup_done; diff --git a/test/BUILD b/test/BUILD index 0a66bf3d53..8262d080fa 100644 --- a/test/BUILD +++ b/test/BUILD @@ -25,14 +25,14 @@ PER_SRC_COPTS = { "donotoptimize_test.cc": ["-O3"], } -TEST_ARGS = ["--benchmark_min_time=0.01"] +TEST_ARGS = ["--benchmark_min_time=0.01s"] -PER_SRC_TEST_ARGS = ({ +PER_SRC_TEST_ARGS = { "user_counters_tabular_test.cc": ["--benchmark_counters_tabular=true"], "repetitions_test.cc": [" --benchmark_repetitions=3"], - "spec_arg_test.cc" : ["--benchmark_filter=BM_NotChosen"], - "spec_arg_verbosity_test.cc" : ["--v=42"], -}) + "spec_arg_test.cc": ["--benchmark_filter=BM_NotChosen"], + "spec_arg_verbosity_test.cc": ["--v=42"], +} cc_library( name = "output_test_helper", @@ -58,14 +58,14 @@ cc_library( copts = select({ "//:windows": [], "//conditions:default": TEST_COPTS, - }) + PER_SRC_COPTS.get(test_src, []) , + }) + PER_SRC_COPTS.get(test_src, []), deps = [ ":output_test_helper", "//:benchmark", "//:benchmark_internal_headers", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", - ] + ], # FIXME: Add support for assembly tests to bazel. # See Issue #556 # https://github.com/google/benchmark/issues/556 @@ -85,6 +85,10 @@ cc_test( size = "small", srcs = ["cxx03_test.cc"], copts = TEST_COPTS + ["-std=c++03"], + target_compatible_with = select({ + "//:windows": ["@platforms//:incompatible"], + "//conditions:default": [], + }), deps = [ ":output_test_helper", "//:benchmark", @@ -92,10 +96,6 @@ cc_test( "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", ], - target_compatible_with = select({ - "//:windows": ["@platforms//:incompatible"], - "//conditions:default": [], - }) ) cc_test( diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a49ab195e7..cfef13bd77 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -61,7 +61,7 @@ endmacro(compile_output_test) # Demonstration executable compile_benchmark_test(benchmark_test) -add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01) +add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01s) compile_benchmark_test(spec_arg_test) add_test(NAME spec_arg COMMAND spec_arg_test --benchmark_filter=BM_NotChosen) @@ -74,10 +74,16 @@ add_test(NAME benchmark_setup_teardown COMMAND benchmark_setup_teardown_test) compile_benchmark_test(filter_test) macro(add_filter_test name filter expect) - add_test(NAME ${name} COMMAND filter_test --benchmark_min_time=0.01 --benchmark_filter=${filter} ${expect}) + add_test(NAME ${name} COMMAND filter_test --benchmark_min_time=0.01s --benchmark_filter=${filter} ${expect}) add_test(NAME ${name}_list_only COMMAND filter_test --benchmark_list_tests --benchmark_filter=${filter} ${expect}) endmacro(add_filter_test) +compile_benchmark_test(benchmark_min_time_flag_time_test) +add_test(NAME min_time_flag_time COMMAND benchmark_min_time_flag_time_test) + +compile_benchmark_test(benchmark_min_time_flag_iters_test) +add_test(NAME min_time_flag_iters COMMAND benchmark_min_time_flag_iters_test) + add_filter_test(filter_simple "Foo" 3) add_filter_test(filter_simple_negative "-Foo" 2) add_filter_test(filter_suffix "BM_.*" 4) @@ -98,19 +104,19 @@ add_filter_test(filter_regex_end ".*Ba$" 1) add_filter_test(filter_regex_end_negative "-.*Ba$" 4) compile_benchmark_test(options_test) -add_test(NAME options_benchmarks COMMAND options_test --benchmark_min_time=0.01) +add_test(NAME options_benchmarks COMMAND options_test --benchmark_min_time=0.01s) compile_benchmark_test(basic_test) -add_test(NAME basic_benchmark COMMAND basic_test --benchmark_min_time=0.01) +add_test(NAME basic_benchmark COMMAND basic_test --benchmark_min_time=0.01s) compile_output_test(repetitions_test) -add_test(NAME repetitions_benchmark COMMAND repetitions_test --benchmark_min_time=0.01 --benchmark_repetitions=3) +add_test(NAME repetitions_benchmark COMMAND repetitions_test --benchmark_min_time=0.01s --benchmark_repetitions=3) compile_benchmark_test(diagnostics_test) -add_test(NAME diagnostics_test COMMAND diagnostics_test --benchmark_min_time=0.01) +add_test(NAME diagnostics_test COMMAND diagnostics_test --benchmark_min_time=0.01s) compile_benchmark_test(skip_with_error_test) -add_test(NAME skip_with_error_test COMMAND skip_with_error_test --benchmark_min_time=0.01) +add_test(NAME skip_with_error_test COMMAND skip_with_error_test --benchmark_min_time=0.01s) compile_benchmark_test(donotoptimize_test) # Some of the issues with DoNotOptimize only occur when optimization is enabled @@ -118,55 +124,55 @@ check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) if (BENCHMARK_HAS_O3_FLAG) set_target_properties(donotoptimize_test PROPERTIES COMPILE_FLAGS "-O3") endif() -add_test(NAME donotoptimize_test COMMAND donotoptimize_test --benchmark_min_time=0.01) +add_test(NAME donotoptimize_test COMMAND donotoptimize_test --benchmark_min_time=0.01s) compile_benchmark_test(fixture_test) -add_test(NAME fixture_test COMMAND fixture_test --benchmark_min_time=0.01) +add_test(NAME fixture_test COMMAND fixture_test --benchmark_min_time=0.01s) compile_benchmark_test(register_benchmark_test) -add_test(NAME register_benchmark_test COMMAND register_benchmark_test --benchmark_min_time=0.01) +add_test(NAME register_benchmark_test COMMAND register_benchmark_test --benchmark_min_time=0.01s) compile_benchmark_test(map_test) -add_test(NAME map_test COMMAND map_test --benchmark_min_time=0.01) +add_test(NAME map_test COMMAND map_test --benchmark_min_time=0.01s) compile_benchmark_test(multiple_ranges_test) -add_test(NAME multiple_ranges_test COMMAND multiple_ranges_test --benchmark_min_time=0.01) +add_test(NAME multiple_ranges_test COMMAND multiple_ranges_test --benchmark_min_time=0.01s) compile_benchmark_test(args_product_test) -add_test(NAME args_product_test COMMAND args_product_test --benchmark_min_time=0.01) +add_test(NAME args_product_test COMMAND args_product_test --benchmark_min_time=0.01s) compile_benchmark_test_with_main(link_main_test) -add_test(NAME link_main_test COMMAND link_main_test --benchmark_min_time=0.01) +add_test(NAME link_main_test COMMAND link_main_test --benchmark_min_time=0.01s) compile_output_test(reporter_output_test) -add_test(NAME reporter_output_test COMMAND reporter_output_test --benchmark_min_time=0.01) +add_test(NAME reporter_output_test COMMAND reporter_output_test --benchmark_min_time=0.01s) compile_output_test(templated_fixture_test) -add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01) +add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01s) compile_output_test(user_counters_test) -add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01) +add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s) compile_output_test(perf_counters_test) -add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01 --benchmark_perf_counters=CYCLES,BRANCHES) +add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,BRANCHES) compile_output_test(internal_threading_test) -add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01) +add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01s) compile_output_test(report_aggregates_only_test) -add_test(NAME report_aggregates_only_test COMMAND report_aggregates_only_test --benchmark_min_time=0.01) +add_test(NAME report_aggregates_only_test COMMAND report_aggregates_only_test --benchmark_min_time=0.01s) compile_output_test(display_aggregates_only_test) -add_test(NAME display_aggregates_only_test COMMAND display_aggregates_only_test --benchmark_min_time=0.01) +add_test(NAME display_aggregates_only_test COMMAND display_aggregates_only_test --benchmark_min_time=0.01s) compile_output_test(user_counters_tabular_test) -add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.01) +add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.01s) compile_output_test(user_counters_thousands_test) -add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test --benchmark_min_time=0.01) +add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test --benchmark_min_time=0.01s) compile_output_test(memory_manager_test) -add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01) +add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s) # MSVC does not allow to set the language standard to C++98/03. if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") @@ -191,14 +197,14 @@ if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(DISABLE_LTO_WARNINGS "${DISABLE_LTO_WARNINGS} -Wno-lto-type-mismatch") endif() set_target_properties(cxx03_test PROPERTIES LINK_FLAGS "${DISABLE_LTO_WARNINGS}") - add_test(NAME cxx03 COMMAND cxx03_test --benchmark_min_time=0.01) + add_test(NAME cxx03 COMMAND cxx03_test --benchmark_min_time=0.01s) endif() # Attempt to work around flaky test failures when running on Appveyor servers. if (DEFINED ENV{APPVEYOR}) - set(COMPLEXITY_MIN_TIME "0.5") + set(COMPLEXITY_MIN_TIME "0.5s") else() - set(COMPLEXITY_MIN_TIME "0.01") + set(COMPLEXITY_MIN_TIME "0.01s") endif() compile_output_test(complexity_test) add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=${COMPLEXITY_MIN_TIME}) @@ -227,6 +233,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS) add_gtest(string_util_gtest) add_gtest(perf_counters_gtest) add_gtest(time_unit_gtest) + add_gtest(min_time_parse_gtest) endif(BENCHMARK_ENABLE_GTEST_TESTS) ############################################################################### diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc new file mode 100644 index 0000000000..4ed768c736 --- /dev/null +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" + +// Tests that we can specify the number of iterations with +// --benchmark_min_time=x. +namespace { + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + return ConsoleReporter::ReportContext(context); + }; + + virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + assert(report.size() == 1); + iter_nums_.push_back(report[0].iterations); + ConsoleReporter::ReportRuns(report); + }; + + TestReporter() {} + + virtual ~TestReporter() {} + + const std::vector& GetIters() const { return iter_nums_; } + + private: + std::vector iter_nums_; +}; + +} // end namespace + +static void BM_MyBench(benchmark::State& state) { + for (auto s : state) { + } +} +BENCHMARK(BM_MyBench); + +int main(int argc, char** argv) { + // Make a fake argv and append the new --benchmark_min_time= to it. + int fake_argc = argc + 1; + const char** fake_argv = new const char*[fake_argc]; + for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; + fake_argv[argc] = "--benchmark_min_time=4x"; + + benchmark::Initialize(&fake_argc, const_cast(fake_argv)); + + TestReporter test_reporter; + const size_t returned_count = + benchmark::RunSpecifiedBenchmarks(&test_reporter, "BM_MyBench"); + assert(returned_count == 1); + + // Check the executed iters. + const std::vector iters = test_reporter.GetIters(); + assert(!iters.empty() && iters[0] == 4); + + delete[] fake_argv; + return 0; +} diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc new file mode 100644 index 0000000000..b602031a8d --- /dev/null +++ b/test/benchmark_min_time_flag_time_test.cc @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" + +// Tests that we can specify the min time with +// --benchmark_min_time= (no suffix needed) OR +// --benchmark_min_time=s +namespace { + +// This is from benchmark.h +typedef int64_t IterationCount; + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + return ConsoleReporter::ReportContext(context); + }; + + virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + assert(report.size() == 1); + ConsoleReporter::ReportRuns(report); + }; + + virtual void ReportRunsConfig(double min_time, bool has_explicit_iters, + IterationCount iters) BENCHMARK_OVERRIDE { + min_times_.push_back(min_time); + } + + TestReporter() {} + + virtual ~TestReporter() {} + + const std::vector& GetMinTimes() const { return min_times_; } + + private: + std::vector min_times_; +}; + +bool AlmostEqual(double a, double b) { + return std::fabs(a - b) < std::numeric_limits::epsilon(); +} + +void DoTestHelper(int* argc, const char** argv, double expected) { + benchmark::Initialize(argc, const_cast(argv)); + + TestReporter test_reporter; + const size_t returned_count = + benchmark::RunSpecifiedBenchmarks(&test_reporter, "BM_MyBench"); + assert(returned_count == 1); + + // Check the min_time + const std::vector& min_times = test_reporter.GetMinTimes(); + assert(!min_times.empty() && AlmostEqual(min_times[0], expected)); +} + +} // end namespace + +static void BM_MyBench(benchmark::State& state) { + for (auto s : state) { + } +} +BENCHMARK(BM_MyBench); + +int main(int argc, char** argv) { + // Make a fake argv and append the new --benchmark_min_time= to it. + int fake_argc = argc + 1; + const char** fake_argv = new const char*[fake_argc]; + + for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; + + const char* no_suffix = "--benchmark_min_time=4"; + const char* with_suffix = "--benchmark_min_time=4.0s"; + double expected = 4.0; + + fake_argv[argc] = no_suffix; + DoTestHelper(&fake_argc, fake_argv, expected); + + fake_argv[argc] = with_suffix; + DoTestHelper(&fake_argc, fake_argv, expected); + + delete[] fake_argv; + return 0; +} diff --git a/test/min_time_parse_gtest.cc b/test/min_time_parse_gtest.cc new file mode 100644 index 0000000000..e2bdf67850 --- /dev/null +++ b/test/min_time_parse_gtest.cc @@ -0,0 +1,30 @@ +#include "../src/benchmark_runner.h" +#include "gtest/gtest.h" + +namespace { + +TEST(ParseMinTimeTest, InvalidInput) { +#if GTEST_HAS_DEATH_TEST + // Tests only runnable in debug mode (when BM_CHECK is enabled). +#ifndef NDEBUG +#ifndef TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS + ASSERT_DEATH_IF_SUPPORTED( + { benchmark::internal::ParseBenchMinTime("abc"); }, + "Malformed seconds value passed to --benchmark_min_time: `abc`"); + + ASSERT_DEATH_IF_SUPPORTED( + { benchmark::internal::ParseBenchMinTime("123ms"); }, + "Malformed seconds value passed to --benchmark_min_time: `123ms`"); + + ASSERT_DEATH_IF_SUPPORTED( + { benchmark::internal::ParseBenchMinTime("1z"); }, + "Malformed seconds value passed to --benchmark_min_time: `1z`"); + + ASSERT_DEATH_IF_SUPPORTED( + { benchmark::internal::ParseBenchMinTime("1hs"); }, + "Malformed seconds value passed to --benchmark_min_time: `1hs`"); +#endif +#endif +#endif +} +} // namespace From 84c71faa8126e4eedc2bb520352615cb4484d6ad Mon Sep 17 00:00:00 2001 From: hamptonm1 <79232909+hamptonm1@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:10:30 -0500 Subject: [PATCH 066/561] Refactor links which include "master" and change it to "main" (#1540) * Refactor URL links: remove "master" * Replace "master" with "main" --- README.md | 4 ++-- src/colorprint.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 03d5dc31f2..b64048b7d3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![pylint](https://github.com/google/benchmark/workflows/pylint/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Apylint) [![test-bindings](https://github.com/google/benchmark/workflows/test-bindings/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Atest-bindings) -[![Build Status](https://travis-ci.org/google/benchmark.svg?branch=master)](https://travis-ci.org/google/benchmark) +[![Build Status](https://travis-ci.org/google/benchmark.svg?branch=main)](https://travis-ci.org/google/benchmark) [![Coverage Status](https://coveralls.io/repos/google/benchmark/badge.svg)](https://coveralls.io/r/google/benchmark) @@ -33,7 +33,7 @@ To get started, see [Requirements](#requirements) and [Installation](#installation). See [Usage](#usage) for a full example and the [User Guide](docs/user_guide.md) for a more comprehensive feature overview. -It may also help to read the [Google Test documentation](https://github.com/google/googletest/blob/master/docs/primer.md) +It may also help to read the [Google Test documentation](https://github.com/google/googletest/blob/main/docs/primer.md) as some of the structural aspects of the APIs are similar. ## Resources diff --git a/src/colorprint.cc b/src/colorprint.cc index 62e9310a12..9a653c5007 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -163,7 +163,7 @@ bool IsColorTerminal() { #else // On non-Windows platforms, we rely on the TERM variable. This list of // supported TERM values is copied from Google Test: - // . + // . const char* const SUPPORTED_TERM_VALUES[] = { "xterm", "xterm-color", "xterm-256color", "screen", "screen-256color", "tmux", From 6ebd82f2be1e8bf240dcd0f43904aa164dbd1990 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 9 Feb 2023 16:29:10 +0100 Subject: [PATCH 067/561] replace complexity with simplicity for faster libc++ setup (#1539) * replace complexity with simplicity for faster libc++ setup * fix script reference * ignore error from stdlib in clang+asan * add missing run --- .github/.libcxx-setup.sh | 24 ------------------------ .github/libcxx-setup.sh | 27 +++++++++++++++++++++++++++ .github/workflows/sanitizer.yml | 8 +++++++- 3 files changed, 34 insertions(+), 25 deletions(-) delete mode 100755 .github/.libcxx-setup.sh create mode 100755 .github/libcxx-setup.sh diff --git a/.github/.libcxx-setup.sh b/.github/.libcxx-setup.sh deleted file mode 100755 index c173111f63..0000000000 --- a/.github/.libcxx-setup.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -# Checkout LLVM sources -git clone --depth=1 https://github.com/llvm/llvm-project.git llvm-project - -# Setup libc++ options -if [ -z "$BUILD_32_BITS" ]; then - export BUILD_32_BITS=OFF && echo disabling 32 bit build -fi - -# Build and install libc++ (Use unstable ABI for better sanitizer coverage) -cd ./llvm-project -cmake -DCMAKE_C_COMPILER=${CC} \ - -DCMAKE_CXX_COMPILER=${CXX} \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DLIBCXX_ABI_UNSTABLE=OFF \ - -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ - -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ - -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \ - -S llvm -B llvm-build -G "Unix Makefiles" -make -C llvm-build -j3 cxx cxxabi -sudo make -C llvm-build install-cxx install-cxxabi -cd .. diff --git a/.github/libcxx-setup.sh b/.github/libcxx-setup.sh new file mode 100755 index 0000000000..e39e310e41 --- /dev/null +++ b/.github/libcxx-setup.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Checkout LLVM sources +#git clone --depth=1 https://github.com/llvm/llvm-project.git llvm-project +# +## Setup libc++ options +#if [ -z "$BUILD_32_BITS" ]; then +# export BUILD_32_BITS=OFF && echo disabling 32 bit build +#fi +# +## Build and install libc++ (Use unstable ABI for better sanitizer coverage) +#cd ./llvm-project +#cmake -DCMAKE_C_COMPILER=${CC} \ +# -DCMAKE_CXX_COMPILER=${CXX} \ +# -DCMAKE_BUILD_TYPE=RelWithDebInfo \ +# -DCMAKE_INSTALL_PREFIX=/usr \ +# -DLIBCXX_ABI_UNSTABLE=OFF \ +# -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ +# -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ +# -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \ +# -S llvm -B llvm-build -G "Unix Makefiles" +#make -C llvm-build -j3 cxx cxxabi +#sudo make -C llvm-build install-cxx install-cxxabi +#cd .. + +sudo apt update +sudo apt -y install libc++-dev libc++abi-dev diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 7fff2cea9c..4df2301809 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -45,6 +45,12 @@ jobs: echo "EXTRA_FLAGS=-g -O2 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all" >> $GITHUB_ENV echo "LIBCXX_SANITIZER=Thread" >> $GITHUB_ENV + - name: fine-tune asan options + # in clang+asan we get an error from std::regex. ignore it. + if: matrix.sanitizer == 'asan' && matrix.compiler == 'clang' + run: | + echo "ASAN_OPTIONS=alloc_dealloc_mismatch=0" >> $GITHUB_ENV + - name: setup clang if: matrix.compiler == 'clang' uses: egor-tensin/setup-clang@v1 @@ -68,7 +74,7 @@ jobs: - name: install llvm stuff if: matrix.compiler == 'clang' run: | - "${GITHUB_WORKSPACE}/.github/.libcxx-setup.sh" + "${GITHUB_WORKSPACE}/.github/libcxx-setup.sh" echo "EXTRA_CXX_FLAGS=\"-stdlib=libc++\"" >> $GITHUB_ENV - name: create build environment From 0ce66c00f5e41ba7480e3ad6b6673d5b94abf412 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 9 Feb 2023 16:52:03 +0100 Subject: [PATCH 068/561] update github actions to latest versions (#1541) --- .github/workflows/bazel.yml | 4 ++-- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/pylint.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 1d0864b942..9e31c9012b 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -14,10 +14,10 @@ jobs: os: [ubuntu-latest, macos-latest, windows-2022] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: mount bazel cache - uses: actions/cache@v2.0.0 + uses: actions/cache@v3 env: cache-name: bazel-cache with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index b6096c2b54..97e4d8ea63 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -17,7 +17,7 @@ jobs: os: [ubuntu-22.04, ubuntu-20.04] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 764192f5a7..65b2e6b484 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -23,7 +23,7 @@ jobs: lib: ['shared', 'static'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 75775c7cfc..77ce1f8cd4 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: DoozyX/clang-format-lint-action@v0.13 with: source: './include/benchmark ./src ./test' diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 978171df0d..2eaab9c1e2 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index e15e69e3ca..da92c46a2d 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Installing build dependencies run: | diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index f6d368b48e..c6939b50f3 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python 3.8 uses: actions/setup-python@v1 with: diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 4df2301809..4cb93f4a47 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: compiler: ['clang', 'gcc'] # TODO: add 'msan' above. currently failing and needs investigation. steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: configure msan env if: matrix.sanitizer == 'msan' From bd721f9859e50b261b7afe8a262a11c25b292aa5 Mon Sep 17 00:00:00 2001 From: Yury Fedorov <114264320+yuryf-google@users.noreply.github.com> Date: Mon, 13 Feb 2023 12:18:07 +0100 Subject: [PATCH 069/561] Removing warnings appearing with C++20 / CLang 15 (#1542) * Removing warnings appearing with C++20 / CLang 15 ``` [ 70%] Building CXX object _deps/benchmark-build/test/CMakeFiles/benchmark_min_time_flag_time_test.dir/benchmark_min_time_flag_time_test.cc.o /home/xxx/cpp/_deps/benchmark-src/test/benchmark_min_time_flag_time_test.cc:31:55: warning: unused parameter 'has_explicit_iters' [-Wunused-parameter] virtual void ReportRunsConfig(double min_time, bool has_explicit_iters, ^ /home/xxx/cpp/_deps/benchmark-src/test/benchmark_min_time_flag_time_test.cc:32:48: warning: unused parameter 'iters' [-Wunused-parameter] IterationCount iters) BENCHMARK_OVERRIDE { ^ 2 warnings generated. ``` ``` [ 70%] Building CXX object _deps/benchmark-build/test/CMakeFiles/benchmark_min_time_flag_iters_test.dir/benchmark_min_time_flag_iters_test.cc.o /home/xxx/cpp/_deps/benchmark-src/test/benchmark_min_time_flag_iters_test.cc:22:36: warning: implicit conversion loses integer precision: 'const benchmark::IterationCount' (aka 'const long') to 'std::vector::value_type' (aka 'int') [-Wshorten-64-to-32] iter_nums_.push_back(report[0].iterations); ~~~~~~~~~ ~~~~~~~~~~^~~~~~~~~~ 1 warning generated. ``` * Refactoring to get the proper type of collection * Refactoring to get the proper type of collection * clang format * bug fix in main --- test/benchmark_min_time_flag_iters_test.cc | 8 +++++--- test/benchmark_min_time_flag_time_test.cc | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index 4ed768c736..eb9414acdb 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -27,10 +27,12 @@ class TestReporter : public benchmark::ConsoleReporter { virtual ~TestReporter() {} - const std::vector& GetIters() const { return iter_nums_; } + const std::vector& GetIters() const { + return iter_nums_; + } private: - std::vector iter_nums_; + std::vector iter_nums_; }; } // end namespace @@ -56,7 +58,7 @@ int main(int argc, char** argv) { assert(returned_count == 1); // Check the executed iters. - const std::vector iters = test_reporter.GetIters(); + const std::vector iters = test_reporter.GetIters(); assert(!iters.empty() && iters[0] == 4); delete[] fake_argv; diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index b602031a8d..b172cccba7 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -28,8 +28,8 @@ class TestReporter : public benchmark::ConsoleReporter { ConsoleReporter::ReportRuns(report); }; - virtual void ReportRunsConfig(double min_time, bool has_explicit_iters, - IterationCount iters) BENCHMARK_OVERRIDE { + virtual void ReportRunsConfig(double min_time, bool /* has_explicit_iters */, + IterationCount /* iters */) BENCHMARK_OVERRIDE { min_times_.push_back(min_time); } From 07996a8adc21cf88b254ed13b69c7e05b5dcd659 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Thu, 16 Feb 2023 13:35:21 -0500 Subject: [PATCH 070/561] Add missing parentheses in ParseBenchMinTime() (#1545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous code was triggering a warning in Debug builds where NDEBUG is not defined and BM_CHECK() is included: benchmark/src/benchmark_runner.cc: In function ‘benchmark::internal::BenchTimeType benchmark::internal::ParseBenchMinTime(const std::string&)’: benchmark/src/benchmark_runner.cc:212:24: error: suggest parentheses around ‘&&’ within ‘||’ [-Werror=parentheses] 212 | (has_suffix && *p_end == 's' || *p_end == '\0')) | ~~~~~~~~~~~^~~~~~~~~~~~~~~~ benchmark/src/check.h:82:4: note: in definition of macro ‘BM_CHECK’ 82 | (b ? ::benchmark::internal::GetNullLogInstance() \ | ^ Add parenthesis around the && expression. Also fix a spelling error and move the comma in the preceding comment to improve clarity. Tested: - cmake -E make_directory build - cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Debug ../ - cmake --build "build" --config Debug - cmake -E chdir "build" ctest --build-config Debug --- src/benchmark_runner.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index eb0d9cbe79..09975a9eb6 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -206,10 +206,10 @@ BenchTimeType ParseBenchMinTime(const std::string& value) { errno = 0; double min_time = std::strtod(time_str, &p_end); - // After a successfull parse, p_end should point to the suffix 's' - // or the end of the string, if the suffix was omitted. + // After a successful parse, p_end should point to the suffix 's', + // or the end of the string if the suffix was omitted. BM_CHECK(errno == 0 && p_end != nullptr && - (has_suffix && *p_end == 's' || *p_end == '\0')) + ((has_suffix && *p_end == 's') || *p_end == '\0')) << "Malformed seconds value passed to --benchmark_min_time: `" << value << "`. Expected --benchmark_min_time=x."; From 1079d96989af2bee0dec7b1f946a6be735d884c9 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 16 Feb 2023 18:54:09 +0000 Subject: [PATCH 071/561] Werror all the time (#1546) --- CMakeLists.txt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7a17d8e51..59e86b2415 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,9 +190,7 @@ else() add_cxx_compiler_flag(-Wshadow) add_cxx_compiler_flag(-Wfloat-equal) if(BENCHMARK_ENABLE_WERROR) - add_cxx_compiler_flag(-Werror RELEASE) - add_cxx_compiler_flag(-Werror RELWITHDEBINFO) - add_cxx_compiler_flag(-Werror MINSIZEREL) + add_cxx_compiler_flag(-Werror) endif() if (NOT BENCHMARK_ENABLE_TESTING) # Disable warning when compiling tests as gtest does not use 'override'. @@ -213,9 +211,7 @@ else() endif() # Disable deprecation warnings for release builds (when -Werror is enabled). if(BENCHMARK_ENABLE_WERROR) - add_cxx_compiler_flag(-Wno-deprecated RELEASE) - add_cxx_compiler_flag(-Wno-deprecated RELWITHDEBINFO) - add_cxx_compiler_flag(-Wno-deprecated MINSIZEREL) + add_cxx_compiler_flag(-Wno-deprecated) endif() if (NOT BENCHMARK_ENABLE_EXCEPTIONS) add_cxx_compiler_flag(-fno-exceptions) From b111d01c1b4cc86da08672a68cddcbcc1cedd742 Mon Sep 17 00:00:00 2001 From: Carlos O'Ryan Date: Fri, 17 Feb 2023 08:38:53 -0500 Subject: [PATCH 072/561] cleanup: support CMake >= 3.10 (#1544) * cleanup: support CMake >= 3.10 This aligns the project with the CMake support policies in: https://opensource.google/documentation/policies/cplusplus-support I also simplied the management of CMake policies. Most of the overriden policies (anything <= CMP0067) are enabled by default when you require CMake >= 3.10. But it is easier to just declare that you will accept newer policies when they are available using the `...3.22` notation. * Address review comments * inlined links --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- CMakeLists.txt | 17 ++--------------- docs/dependencies.md | 21 ++++++++------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59e86b2415..ccec880c56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,5 @@ -cmake_minimum_required (VERSION 3.16.3) - -foreach(p - CMP0048 # OK to clear PROJECT_VERSION on project() - CMP0054 # CMake 3.1 - CMP0056 # export EXE_LINKER_FLAGS to try_run - CMP0057 # Support no if() IN_LIST operator - CMP0063 # Honor visibility properties for all targets - CMP0067 # Honor language standard in try_compile() source file signature - CMP0077 # Allow option() overrides in importing projects - ) - if(POLICY ${p}) - cmake_policy(SET ${p} NEW) - endif() -endforeach() +# Require CMake 3.10. If available, use the policies up to CMake 3.22. +cmake_minimum_required (VERSION 3.10...3.22) project (benchmark VERSION 1.7.1 LANGUAGES CXX) diff --git a/docs/dependencies.md b/docs/dependencies.md index 98aae42af6..07760e10e3 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -1,18 +1,13 @@ # Build tool dependency policy -To ensure the broadest compatibility when building the benchmark library, but -still allow forward progress, we require any build tooling to be available for: +We follow the [Foundational C++ support policy](https://opensource.google/documentation/policies/cplusplus-support) for our build tools. In +particular the ["Build Systems" section](https://opensource.google/documentation/policies/cplusplus-support#build-systems). -* Debian stable _and_ -* The last two Ubuntu LTS releases +## CMake -Currently, this means using build tool versions that are available for Ubuntu -Ubuntu 20.04 (Focal Fossa), Ubuntu 22.04 (Jammy Jellyfish) and Debian 11.4 (bullseye). - -## cmake -The current supported version is cmake 3.16.3 as of 2022-08-10. - -* 3.16.3 (ubuntu 20.04) -* 3.18.4 (debian 11.4) -* 3.22.1 (ubuntu 22.04) +The current supported version is CMake 3.10 as of 2023-08-10. Most modern +distributions include newer versions, for example: +* Ubuntu 20.04 provides CMake 3.16.3 +* Debian 11.4 provides CMake 3.18.4 +* Ubuntu 22.04 provides CMake 3.22.1 From 3b19d7222db7babfdc9b3949408b2294c3bbb540 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Tue, 21 Feb 2023 19:30:28 +0800 Subject: [PATCH 073/561] Fix CPU frequency estimation on riscv (#1549) * Fix CPU frequency estimation on riscv * Cleanup code for CPU frequency estimation * Fix use before definition of the macro * Move the platform definitions back * Fix compilation error on windows * Remove unused sleep.h and sleep.cc --- CMakeLists.txt | 1 + cmake/pthread_affinity.cpp | 16 +++++ src/CMakeLists.txt | 5 ++ src/internal_macros.h | 4 ++ src/sleep.cc | 66 --------------------- src/sleep.h | 15 ----- src/sysinfo.cc | 116 +++++++++++++++++++++++++++++++++++-- src/timers.cc | 1 - 8 files changed, 138 insertions(+), 86 deletions(-) create mode 100644 cmake/pthread_affinity.cpp delete mode 100644 src/sleep.cc delete mode 100644 src/sleep.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ccec880c56..6e7701e32d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,6 +307,7 @@ cxx_feature_check(STEADY_CLOCK) # Ensure we have pthreads set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) +cxx_feature_check(PTHREAD_AFFINITY) if (BENCHMARK_ENABLE_LIBPFM) find_package(PFM) diff --git a/cmake/pthread_affinity.cpp b/cmake/pthread_affinity.cpp new file mode 100644 index 0000000000..7b143bc021 --- /dev/null +++ b/cmake/pthread_affinity.cpp @@ -0,0 +1,16 @@ +#include +int main() { + cpu_set_t set; + CPU_ZERO(&set); + for (int i = 0; i < CPU_SETSIZE; ++i) { + CPU_SET(i, &set); + CPU_CLR(i, &set); + } + pthread_t self = pthread_self(); + int ret; + ret = pthread_getaffinity_np(self, sizeof(set), &set); + if (ret != 0) return ret; + ret = pthread_setaffinity_np(self, sizeof(set), &set); + if (ret != 0) return ret; + return 0; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7f2c88b5ac..91ea5f42b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,11 @@ if (HAVE_LIBPFM) target_compile_definitions(benchmark PRIVATE -DHAVE_LIBPFM) endif() +# pthread affinity, if available +if(HAVE_PTHREAD_AFFINITY) + target_compile_definitions(benchmark PRIVATE -DBENCHMARK_HAS_PTHREAD_AFFINITY) +endif() + # Link threads. target_link_libraries(benchmark PRIVATE Threads::Threads) diff --git a/src/internal_macros.h b/src/internal_macros.h index 396a390afb..658f157339 100644 --- a/src/internal_macros.h +++ b/src/internal_macros.h @@ -42,6 +42,10 @@ #define BENCHMARK_OS_CYGWIN 1 #elif defined(_WIN32) #define BENCHMARK_OS_WINDOWS 1 + // WINAPI_FAMILY_PARTITION is defined in winapifamily.h. + // We include windows.h which implicitly includes winapifamily.h for compatibility. + #define NOMINMAX + #include #if defined(WINAPI_FAMILY_PARTITION) #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define BENCHMARK_OS_WINDOWS_WIN32 1 diff --git a/src/sleep.cc b/src/sleep.cc deleted file mode 100644 index ab59000f24..0000000000 --- a/src/sleep.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "sleep.h" - -#include -#include -#include - -#include "internal_macros.h" - -#ifdef BENCHMARK_OS_WINDOWS -#include -#endif - -#ifdef BENCHMARK_OS_ZOS -#include -#endif - -namespace benchmark { -#ifdef BENCHMARK_OS_WINDOWS -// Window's Sleep takes milliseconds argument. -void SleepForMilliseconds(int milliseconds) { Sleep(milliseconds); } -void SleepForSeconds(double seconds) { - SleepForMilliseconds(static_cast(kNumMillisPerSecond * seconds)); -} -#else // BENCHMARK_OS_WINDOWS -void SleepForMicroseconds(int microseconds) { -#ifdef BENCHMARK_OS_ZOS - // z/OS does not support nanosleep. Instead call sleep() and then usleep() to - // sleep for the remaining microseconds because usleep() will fail if its - // argument is greater than 1000000. - div_t sleepTime = div(microseconds, kNumMicrosPerSecond); - int seconds = sleepTime.quot; - while (seconds != 0) seconds = sleep(seconds); - while (usleep(sleepTime.rem) == -1 && errno == EINTR) - ; -#else - struct timespec sleep_time; - sleep_time.tv_sec = microseconds / kNumMicrosPerSecond; - sleep_time.tv_nsec = (microseconds % kNumMicrosPerSecond) * kNumNanosPerMicro; - while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) - ; // Ignore signals and wait for the full interval to elapse. -#endif -} - -void SleepForMilliseconds(int milliseconds) { - SleepForMicroseconds(milliseconds * kNumMicrosPerMilli); -} - -void SleepForSeconds(double seconds) { - SleepForMicroseconds(static_cast(seconds * kNumMicrosPerSecond)); -} -#endif // BENCHMARK_OS_WINDOWS -} // end namespace benchmark diff --git a/src/sleep.h b/src/sleep.h deleted file mode 100644 index f98551afe2..0000000000 --- a/src/sleep.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef BENCHMARK_SLEEP_H_ -#define BENCHMARK_SLEEP_H_ - -namespace benchmark { -const int kNumMillisPerSecond = 1000; -const int kNumMicrosPerMilli = 1000; -const int kNumMicrosPerSecond = kNumMillisPerSecond * 1000; -const int kNumNanosPerMicro = 1000; -const int kNumNanosPerSecond = kNumNanosPerMicro * kNumMicrosPerSecond; - -void SleepForMilliseconds(int milliseconds); -void SleepForSeconds(double seconds); -} // end namespace benchmark - -#endif // BENCHMARK_SLEEP_H_ diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 59120b72b4..4578cb0fa5 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -46,6 +46,9 @@ #if defined(BENCHMARK_OS_QURT) #include #endif +#if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) +#include +#endif #include #include @@ -62,15 +65,17 @@ #include #include #include +#include #include #include +#include "benchmark/benchmark.h" #include "check.h" #include "cycleclock.h" #include "internal_macros.h" #include "log.h" -#include "sleep.h" #include "string_util.h" +#include "timers.h" namespace benchmark { namespace { @@ -544,6 +549,80 @@ int GetNumCPUs() { BENCHMARK_UNREACHABLE(); } +class ThreadAffinityGuard final { + public: + ThreadAffinityGuard() : reset_affinity(SetAffinity()) { + if (!reset_affinity) + std::cerr << "***WARNING*** Failed to set thread affinity. Estimated CPU " + "frequency may be incorrect." + << std::endl; + } + + ~ThreadAffinityGuard() { + if (!reset_affinity) return; + +#if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) + int ret = pthread_setaffinity_np(self, sizeof(previous_affinity), + &previous_affinity); + if (ret == 0) return; +#elif defined(BENCHMARK_OS_WINDOWS_WIN32) + DWORD_PTR ret = SetThreadAffinityMask(self, previous_affinity); + if (ret != 0) return; +#endif // def BENCHMARK_HAS_PTHREAD_AFFINITY + PrintErrorAndDie("Failed to reset thread affinity"); + } + + ThreadAffinityGuard(ThreadAffinityGuard&&) = delete; + ThreadAffinityGuard(const ThreadAffinityGuard&) = delete; + ThreadAffinityGuard& operator=(ThreadAffinityGuard&&) = delete; + ThreadAffinityGuard& operator=(const ThreadAffinityGuard&) = delete; + + private: + bool SetAffinity() { +#if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) + int ret; + self = pthread_self(); + ret = pthread_getaffinity_np(self, sizeof(previous_affinity), + &previous_affinity); + if (ret != 0) return false; + + cpu_set_t affinity; + memcpy(&affinity, &previous_affinity, sizeof(affinity)); + + bool is_first_cpu = true; + + for (int i = 0; i < CPU_SETSIZE; ++i) + if (CPU_ISSET(i, &affinity)) { + if (is_first_cpu) + is_first_cpu = false; + else + CPU_CLR(i, &affinity); + } + + if (is_first_cpu) return false; + + ret = pthread_setaffinity_np(self, sizeof(affinity), &affinity); + return ret == 0; +#elif defined(BENCHMARK_OS_WINDOWS_WIN32) + self = GetCurrentThread(); + DWORD_PTR mask = static_cast(1) << GetCurrentProcessorNumber(); + previous_affinity = SetThreadAffinityMask(self, mask); + return previous_affinity != 0; +#else + return false; +#endif // def BENCHMARK_HAS_PTHREAD_AFFINITY + } + +#if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) + pthread_t self; + cpu_set_t previous_affinity; +#elif defined(BENCHMARK_OS_WINDOWS_WIN32) + HANDLE self; + DWORD_PTR previous_affinity; +#endif // def BENCHMARK_HAS_PTHREAD_AFFINITY + bool reset_affinity; +}; + double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { // Currently, scaling is only used on linux path here, // suppress diagnostics about it being unused on other paths. @@ -699,10 +778,39 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { return 1000000000; #endif // If we've fallen through, attempt to roughly estimate the CPU clock rate. - static constexpr int estimate_time_ms = 1000; + + // Make sure to use the same cycle counter when starting and stopping the + // cycle timer. We just pin the current thread to a cpu in the previous + // affinity set. + ThreadAffinityGuard affinity_guard; + + static constexpr double estimate_time_s = 1.0; + const double start_time = ChronoClockNow(); const auto start_ticks = cycleclock::Now(); - SleepForMilliseconds(estimate_time_ms); - return static_cast(cycleclock::Now() - start_ticks); + + // Impose load instead of calling sleep() to make sure the cycle counter + // works. + using PRNG = std::minstd_rand; + using Result = PRNG::result_type; + PRNG rng(static_cast(start_ticks)); + + Result state = 0; + + do { + static constexpr size_t batch_size = 10000; + rng.discard(batch_size); + state += rng(); + + } while (ChronoClockNow() - start_time < estimate_time_s); + + DoNotOptimize(state); + + const auto end_ticks = cycleclock::Now(); + const double end_time = ChronoClockNow(); + + return static_cast(end_ticks - start_ticks) / (end_time - start_time); + // Reset the affinity of current thread when the lifetime of affinity_guard + // ends. } std::vector GetLoadAvg() { diff --git a/src/timers.cc b/src/timers.cc index 379d97dd22..89ddbfb030 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -59,7 +59,6 @@ #include "check.h" #include "log.h" -#include "sleep.h" #include "string_util.h" namespace benchmark { From c71d040549fdd5af99be1934a61859a09f24a6fd Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 28 Feb 2023 12:40:40 +0000 Subject: [PATCH 074/561] add compiler to build-and-test and create min-cmake CI bot (#1550) * add compiler to build-and-test and create min-cmake CI bot * fix CXX env var * downgrade msvc generator for cmake-3.10 * assume windows users have the latest cmake --- .../workflows/build-and-test-min-cmake.yml | 46 +++++++++++++++++++ .github/workflows/build-and-test.yml | 7 ++- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-and-test-min-cmake.yml diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml new file mode 100644 index 0000000000..e3e321752d --- /dev/null +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -0,0 +1,46 @@ +name: build-and-test-min-cmake + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + job: + name: ${{ matrix.os }}.min-cmake + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + + steps: + - uses: actions/checkout@v3 + + - uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.10.0 + + - name: create build environment + run: cmake -E make_directory ${{ runner.workspace }}/_build + + - name: setup cmake initial cache + run: touch compiler-cache.cmake + + - name: configure cmake + env: + CXX: ${{ matrix.compiler }} + shell: bash + working-directory: ${{ runner.workspace }}/_build + run: > + cmake -C ${{ github.workspace }}/compiler-cache.cmake + $GITHUB_WORKSPACE + -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON + -DCMAKE_CXX_VISIBILITY_PRESET=hidden + -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON + + - name: build + shell: bash + working-directory: ${{ runner.workspace }}/_build + run: cmake --build . diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 65b2e6b484..b35200a000 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -19,12 +19,14 @@ jobs: matrix: os: [ubuntu-22.04, ubuntu-20.04, macos-latest] build_type: ['Release', 'Debug'] - compiler: [g++, clang++] + compiler: ['g++', 'clang++'] lib: ['shared', 'static'] steps: - uses: actions/checkout@v3 + - uses: lukka/get-cmake@latest + - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build @@ -42,6 +44,7 @@ jobs: -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DCMAKE_CXX_COMPILER=${{ env.CXX }} -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON @@ -86,6 +89,8 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: lukka/get-cmake@latest + - name: configure cmake run: > cmake -S . -B _build/ From 27c1d8ace94d23ab5d807801f280faea78836533 Mon Sep 17 00:00:00 2001 From: Henrique Bucher <11621271+HFTrader@users.noreply.github.com> Date: Wed, 1 Mar 2023 09:30:41 -0600 Subject: [PATCH 075/561] Implement unlimited number of performance counters (#1552) * Implement unlimited number of performance counters Linux performance counters will limit the number of hardware counters per reading group. For that reason the implementation of PerfCounters is limited to 3. However if only software counters are added, there is no reason to limit the counters. For hardware counters, we create multiple groups and store a vector or leaders in the PerfCounters object. When reading, there is an extra time waste by iterating through all the group leaders. However this should be the same performance as with today. Reading is done by groups and it had to be heavily adjusted with the logic being moved to PerfCounterValues. I created a test for x86-64 and took care of filtering out the events in case it runs in a platform that does not support those counters - the test will not fail. The current tests were already failing (ReOpenExistingCounters, CreateExistingMeasurements and MultiThreaded) on the main branch and they continue to fail after this implementation - I did not fix those not to conflate all here. * Moved the PerfCounterValues::Read() implementation from header to body. * Added missing implementation of PerfCounters::IsCounterSupported when HAVE_LIBPFM is not defined. * Changed comments to reflect the implementation * Removed arg name so it does not generate an error when HAVE_LIBPBM is not defined. * Made loop counter a const reference for clang-tidy * Added missig BENCHMARK_EXPORT to PerfCounterValues --- AUTHORS | 1 + CONTRIBUTORS | 1 + src/perf_counters.cc | 95 +++++++++++++++++++++++++++++++------ src/perf_counters.h | 40 +++++++++++----- test/perf_counters_gtest.cc | 51 ++++++++++++++++++++ 5 files changed, 161 insertions(+), 27 deletions(-) diff --git a/AUTHORS b/AUTHORS index 98d2d98b05..205951bcec 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,6 +32,7 @@ Federico Ficarelli Felix Homann Gergő Szitár Google Inc. +Henrique Bucher International Business Machines Corporation Ismael Jimenez Martinez Jern-Kuan Leong diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 32ab15bbe0..10243a563f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -52,6 +52,7 @@ Felix Homann Geoffrey Martin-Noble Gergő Szitár Hannes Hauswedell +Henrique Bucher Ismael Jimenez Martinez Jern-Kuan Leong JianXiong Zhou diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 06351b694d..2ce4f7e073 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -29,10 +29,48 @@ namespace internal { constexpr size_t PerfCounterValues::kMaxCounters; #if defined HAVE_LIBPFM + +size_t PerfCounterValues::Read(const std::vector& leaders) { + // Create a pointer for multiple reads + const size_t bufsize = values_.size() * sizeof(values_[0]); + char* ptr = reinterpret_cast(values_.data()); + size_t size = bufsize; + for (int lead : leaders) { + auto read_bytes = ::read(lead, ptr, size); + if (read_bytes >= ssize_t(sizeof(uint64_t))) { + // Actual data bytes are all bytes minus initial padding + std::size_t data_bytes = read_bytes - sizeof(uint64_t); + // This should be very cheap since it's in hot cache + std::memmove(ptr, ptr + sizeof(uint64_t), data_bytes); + // Increment our counters + ptr += data_bytes; + size -= data_bytes; + } else { + int err = errno; + GetErrorLogInstance() << "Error reading lead " << lead << " errno:" << err + << " " << ::strerror(err) << "\n"; + return 0; + } + } + return (bufsize - size) / sizeof(uint64_t); +} + const bool PerfCounters::kSupported = true; bool PerfCounters::Initialize() { return pfm_initialize() == PFM_SUCCESS; } +bool PerfCounters::IsCounterSupported(const std::string& name) { + perf_event_attr_t attr; + std::memset(&attr, 0, sizeof(attr)); + pfm_perf_encode_arg_t arg; + std::memset(&arg, 0, sizeof(arg)); + arg.attr = &attr; + const int mode = PFM_PLM3; // user mode only + int ret = pfm_get_os_event_encoding(name.c_str(), mode, PFM_OS_PERF_EVENT_EXT, + &arg); + return (ret == PFM_SUCCESS); +} + PerfCounters PerfCounters::Create( const std::vector& counter_names) { if (counter_names.empty()) { @@ -46,13 +84,14 @@ PerfCounters PerfCounters::Create( return NoCounters(); } std::vector counter_ids(counter_names.size()); + std::vector leader_ids; const int mode = PFM_PLM3; // user mode only + int group_id = -1; for (size_t i = 0; i < counter_names.size(); ++i) { - const bool is_first = i == 0; + const bool is_first = (group_id < 0); struct perf_event_attr attr {}; attr.size = sizeof(attr); - const int group_id = !is_first ? counter_ids[0] : -1; const auto& name = counter_names[i]; if (name.empty()) { GetErrorLogInstance() << "A counter name was the empty string\n"; @@ -80,13 +119,25 @@ PerfCounters PerfCounters::Create( attr.read_format = PERF_FORMAT_GROUP; int id = -1; - static constexpr size_t kNrOfSyscallRetries = 5; - // Retry syscall as it was interrupted often (b/64774091). - for (size_t num_retries = 0; num_retries < kNrOfSyscallRetries; - ++num_retries) { - id = perf_event_open(&attr, 0, -1, group_id, 0); - if (id >= 0 || errno != EINTR) { - break; + while (id < 0) { + static constexpr size_t kNrOfSyscallRetries = 5; + // Retry syscall as it was interrupted often (b/64774091). + for (size_t num_retries = 0; num_retries < kNrOfSyscallRetries; + ++num_retries) { + id = perf_event_open(&attr, 0, -1, group_id, 0); + if (id >= 0 || errno != EINTR) { + break; + } + } + if (id < 0) { + // We reached a limit perhaps? + if (group_id >= 0) { + // Create a new group + group_id = -1; + } else { + // Give up, there is nothing else to try + break; + } } } if (id < 0) { @@ -94,31 +145,44 @@ PerfCounters PerfCounters::Create( << "Failed to get a file descriptor for " << name << "\n"; return NoCounters(); } - + if (group_id < 0) { + // This is a leader, store and assign it + leader_ids.push_back(id); + group_id = id; + } counter_ids[i] = id; } - if (ioctl(counter_ids[0], PERF_EVENT_IOC_ENABLE) != 0) { - GetErrorLogInstance() << "Failed to start counters\n"; - return NoCounters(); + for (int lead : leader_ids) { + if (ioctl(lead, PERF_EVENT_IOC_ENABLE) != 0) { + GetErrorLogInstance() << "Failed to start counters\n"; + return NoCounters(); + } } - return PerfCounters(counter_names, std::move(counter_ids)); + return PerfCounters(counter_names, std::move(counter_ids), + std::move(leader_ids)); } void PerfCounters::CloseCounters() const { if (counter_ids_.empty()) { return; } - ioctl(counter_ids_[0], PERF_EVENT_IOC_DISABLE); + for (int lead : leader_ids_) { + ioctl(lead, PERF_EVENT_IOC_DISABLE); + } for (int fd : counter_ids_) { close(fd); } } #else // defined HAVE_LIBPFM +size_t PerfCounterValues::Read(const std::vector&) { return 0; } + const bool PerfCounters::kSupported = false; bool PerfCounters::Initialize() { return false; } +bool PerfCounters::IsCounterSupported(const std::string&) { return false; } + PerfCounters PerfCounters::Create( const std::vector& counter_names) { if (!counter_names.empty()) { @@ -162,6 +226,7 @@ PerfCounters& PerfCounters::operator=(PerfCounters&& other) noexcept { CloseCounters(); counter_ids_ = std::move(other.counter_ids_); + leader_ids_ = std::move(other.leader_ids_); counter_names_ = std::move(other.counter_names_); } return *this; diff --git a/src/perf_counters.h b/src/perf_counters.h index 680555d4b0..aeea350d7f 100644 --- a/src/perf_counters.h +++ b/src/perf_counters.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -44,18 +45,21 @@ namespace internal { // The implementation ensures the storage is inlined, and allows 0-based // indexing into the counter values. // The object is used in conjunction with a PerfCounters object, by passing it -// to Snapshot(). The values are populated such that -// perfCounters->names()[i]'s value is obtained at position i (as given by -// operator[]) of this object. -class PerfCounterValues { +// to Snapshot(). The Read() method relocates individual reads, discarding +// the initial padding from each group leader in the values buffer such that +// all user accesses through the [] operator are correct. +class BENCHMARK_EXPORT PerfCounterValues { public: explicit PerfCounterValues(size_t nr_counters) : nr_counters_(nr_counters) { BM_CHECK_LE(nr_counters_, kMaxCounters); } - uint64_t operator[](size_t pos) const { return values_[kPadding + pos]; } + // We are reading correctly now so the values don't need to skip padding + uint64_t operator[](size_t pos) const { return values_[pos]; } - static constexpr size_t kMaxCounters = 3; + // Increased the maximum to 32 only since the buffer + // is std::array<> backed + static constexpr size_t kMaxCounters = 32; private: friend class PerfCounters; @@ -66,7 +70,14 @@ class PerfCounterValues { sizeof(uint64_t) * (kPadding + nr_counters_)}; } - static constexpr size_t kPadding = 1; + // This reading is complex and as the goal of this class is to + // abstract away the intrincacies of the reading process, this is + // a better place for it + size_t Read(const std::vector& leaders); + + // Move the padding to 2 due to the reading algorithm (1st padding plus a + // current read padding) + static constexpr size_t kPadding = 2; std::array values_; const size_t nr_counters_; }; @@ -92,6 +103,10 @@ class BENCHMARK_EXPORT PerfCounters final { // initialization here. static bool Initialize(); + // Check if the given counter is supported, if the app wants to + // check before passing + static bool IsCounterSupported(const std::string& name); + // Return a PerfCounters object ready to read the counters with the names // specified. The values are user-mode only. The counter name format is // implementation and OS specific. @@ -106,9 +121,7 @@ class BENCHMARK_EXPORT PerfCounters final { #ifndef BENCHMARK_OS_WINDOWS assert(values != nullptr); assert(IsValid()); - auto buffer = values->get_data_buffer(); - auto read_bytes = ::read(counter_ids_[0], buffer.first, buffer.second); - return static_cast(read_bytes) == buffer.second; + return values->Read(leader_ids_) == counter_ids_.size(); #else (void)values; return false; @@ -120,13 +133,16 @@ class BENCHMARK_EXPORT PerfCounters final { private: PerfCounters(const std::vector& counter_names, - std::vector&& counter_ids) - : counter_ids_(std::move(counter_ids)), counter_names_(counter_names) {} + std::vector&& counter_ids, std::vector&& leader_ids) + : counter_ids_(std::move(counter_ids)), + leader_ids_(std::move(leader_ids)), + counter_names_(counter_names) {} PerfCounters() = default; void CloseCounters() const; std::vector counter_ids_; + std::vector leader_ids_; std::vector counter_names_; }; diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index f9e6a6fc96..3d2af00d16 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -190,4 +190,55 @@ TEST(PerfCountersTest, MultiThreaded) { EXPECT_GE(D2[0], 1.9 * D1[0]); EXPECT_GE(D2[1], 1.9 * D1[1]); } + +TEST(PerfCountersTest, HardwareLimits) { + // The test works (i.e. causes read to fail) for the assumptions + // about hardware capabilities (i.e. small number (3-4) hardware + // counters) at this date, + // the same as previous test ReopenExistingCounters. + if (!PerfCounters::kSupported) { + GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + } + EXPECT_TRUE(PerfCounters::Initialize()); + + // Taken straight from `perf list` on x86-64 + // Got all hardware names since these are the problematic ones + std::vector counter_names{"cycles", // leader + "instructions", + "branches", + "L1-dcache-loads", + "L1-dcache-load-misses", + "L1-dcache-prefetches", + "L1-icache-load-misses", // leader + "L1-icache-loads", + "branch-load-misses", + "branch-loads", + "dTLB-load-misses", + "dTLB-loads", + "iTLB-load-misses", // leader + "iTLB-loads", + "branch-instructions", + "branch-misses", + "cache-misses", + "cache-references", + "stalled-cycles-backend", // leader + "stalled-cycles-frontend"}; + + // In the off-chance that some of these values are not supported, + // we filter them out so the test will complete without failure + // albeit it might not actually test the grouping on that platform + std::vector valid_names; + for (const std::string& name : counter_names) { + if (PerfCounters::IsCounterSupported(name)) { + valid_names.push_back(name); + } + } + PerfCountersMeasurement counter(valid_names); + + std::vector> measurements; + + counter.Start(); + EXPECT_TRUE(counter.Stop(measurements)); +} + } // namespace From 2d5012275afec586e20b5c5f108f2d71e8d135a0 Mon Sep 17 00:00:00 2001 From: Henrique Bucher <11621271+HFTrader@users.noreply.github.com> Date: Thu, 2 Mar 2023 08:56:13 -0600 Subject: [PATCH 076/561] Filter performance counter names, not invalidate all (#1554) * Filter performance counter names, not invalidate all Currently, the performance counters are validated while they are being created and one failure returns NoCounters(), ie it effecitvely invalidates all the counters. I would like to propose a new behavior: filter instead. If an invalid name is added to the counter list, or if that particular counter is not supported on this platform, that counter is dropped from the list and an error messages is created, while all the other counters remain active. This will give testers a peace of mind that if one mistake is made or if something is changed or removed from libpfm, their entire test will not be invalidated. This feature gives more tolerance with respect to versioning. Another positive is that testers can now input a superset of all desired counters for all platforms they support and just let Benchmark drop all those that are not supported, although it will create quite a lot of noise down the line, in which case perhaps we should drop silently or make a consolidated, single error line but this was not implemented in this change set. * Removed unused helper type. --- src/perf_counters.cc | 64 +++++++++++++++++++++++++++---------- test/perf_counters_gtest.cc | 46 ++++++++++++++++---------- 2 files changed, 78 insertions(+), 32 deletions(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 2ce4f7e073..38b73ae41b 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -71,32 +71,61 @@ bool PerfCounters::IsCounterSupported(const std::string& name) { return (ret == PFM_SUCCESS); } -PerfCounters PerfCounters::Create( +// Validates all counter names passed, returning only the valid ones +static std::vector validateCounters( const std::vector& counter_names) { - if (counter_names.empty()) { - return NoCounters(); + // All valid names to be returned + std::vector valid_names; + + // Loop through all the given names + int invalid_counter = 0; + for (const std::string& name : counter_names) { + // Check trivial empty + if (name.empty()) { + GetErrorLogInstance() << "A counter name was the empty string\n"; + invalid_counter++; + continue; + } + if (PerfCounters::IsCounterSupported(name)) { + // we are about to push into the valid names vector + // check if we did not reach the maximum + if (valid_names.size() == PerfCounterValues::kMaxCounters) { + GetErrorLogInstance() + << counter_names.size() + << " counters were requested. The maximum is " + << PerfCounterValues::kMaxCounters << " and " + << counter_names.size() - invalid_counter - valid_names.size() + << " will be ignored\n"; + // stop the loop and return what we have already + break; + } + valid_names.push_back(name); + } else { + GetErrorLogInstance() << "Performance counter " << name + << " incorrect or not supported on this platform\n"; + invalid_counter++; + } } - if (counter_names.size() > PerfCounterValues::kMaxCounters) { - GetErrorLogInstance() - << counter_names.size() - << " counters were requested. The minimum is 1, the maximum is " - << PerfCounterValues::kMaxCounters << "\n"; + // RVO should take care of this + return valid_names; +} + +PerfCounters PerfCounters::Create( + const std::vector& counter_names) { + std::vector valid_names = validateCounters(counter_names); + if (valid_names.empty()) { return NoCounters(); } - std::vector counter_ids(counter_names.size()); + std::vector counter_ids(valid_names.size()); std::vector leader_ids; const int mode = PFM_PLM3; // user mode only int group_id = -1; - for (size_t i = 0; i < counter_names.size(); ++i) { + for (size_t i = 0; i < valid_names.size(); ++i) { const bool is_first = (group_id < 0); struct perf_event_attr attr {}; attr.size = sizeof(attr); - const auto& name = counter_names[i]; - if (name.empty()) { - GetErrorLogInstance() << "A counter name was the empty string\n"; - return NoCounters(); - } + const auto& name = valid_names[i]; pfm_perf_encode_arg_t arg{}; arg.attr = &attr; @@ -159,7 +188,7 @@ PerfCounters PerfCounters::Create( } } - return PerfCounters(counter_names, std::move(counter_ids), + return PerfCounters(valid_names, std::move(counter_ids), std::move(leader_ids)); } @@ -198,6 +227,9 @@ Mutex PerfCountersMeasurement::mutex_; int PerfCountersMeasurement::ref_count_ = 0; PerfCounters PerfCountersMeasurement::counters_ = PerfCounters::NoCounters(); +// The validation in PerfCounter::Create will create less counters than passed +// so it should be okay to initialize start_values_ and end_values_ with the +// upper bound as passed PerfCountersMeasurement::PerfCountersMeasurement( const std::vector& counter_names) : start_values_(counter_names.size()), end_values_(counter_names.size()) { diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index 3d2af00d16..e31758def5 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -40,26 +40,40 @@ TEST(PerfCountersTest, NegativeTest) { EXPECT_FALSE(PerfCounters::Create({}).IsValid()); EXPECT_FALSE(PerfCounters::Create({""}).IsValid()); EXPECT_FALSE(PerfCounters::Create({"not a counter name"}).IsValid()); + EXPECT_TRUE(PerfCounters::Create( + {kGenericPerfEvent1, kGenericPerfEvent2, kGenericPerfEvent3}) + .IsValid()); { - EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, - kGenericPerfEvent3}) - .IsValid()); + auto counter = + PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1}); + EXPECT_TRUE(counter.IsValid()); + EXPECT_EQ(counter.num_counters(), 2); + EXPECT_EQ(counter.names(), std::vector( + {kGenericPerfEvent2, kGenericPerfEvent1})); + } + { + auto counter = PerfCounters::Create( + {kGenericPerfEvent3, "not a counter name", kGenericPerfEvent1}); + EXPECT_TRUE(counter.IsValid()); + EXPECT_EQ(counter.num_counters(), 2); + EXPECT_EQ(counter.names(), std::vector( + {kGenericPerfEvent3, kGenericPerfEvent1})); } - EXPECT_FALSE( - PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1}) - .IsValid()); - EXPECT_FALSE(PerfCounters::Create({kGenericPerfEvent3, "not a counter name", - kGenericPerfEvent1}) - .IsValid()); { EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, kGenericPerfEvent3}) .IsValid()); } - EXPECT_FALSE( - PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, - kGenericPerfEvent3, "MISPREDICTED_BRANCH_RETIRED"}) - .IsValid()); + { + auto counter = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, + kGenericPerfEvent3, + "MISPREDICTED_BRANCH_RETIRED"}); + EXPECT_TRUE(counter.IsValid()); + EXPECT_EQ(counter.num_counters(), 3); + EXPECT_EQ(counter.names(), + std::vector({kGenericPerfEvent1, kGenericPerfEvent2, + kGenericPerfEvent3})); + } } TEST(PerfCountersTest, Read1Counter) { @@ -157,9 +171,9 @@ void measure(size_t threadcount, PerfCounterValues* values1, auto work = [&]() { BM_CHECK(do_work() > 1000); }; // We need to first set up the counters, then start the threads, so the - // threads would inherit the counters. But later, we need to first destroy the - // thread pool (so all the work finishes), then measure the counters. So the - // scopes overlap, and we need to explicitly control the scope of the + // threads would inherit the counters. But later, we need to first destroy + // the thread pool (so all the work finishes), then measure the counters. So + // the scopes overlap, and we need to explicitly control the scope of the // threadpool. auto counters = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent3}); From 9885aefb96effeb60c4e8c005e7b52c455458c10 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 6 Mar 2023 14:47:54 +0000 Subject: [PATCH 077/561] get rid of warnings in tests (#1562) --- test/basic_test.cc | 3 ++- test/complexity_test.cc | 8 +++++--- test/diagnostics_test.cc | 6 ++++-- test/donotoptimize_test.cc | 29 ++++++----------------------- test/link_main_test.cc | 3 ++- test/map_test.cc | 6 ++++-- test/memory_manager_test.cc | 3 ++- test/perf_counters_test.cc | 3 ++- test/reporter_output_test.cc | 9 ++++++--- test/skip_with_error_test.cc | 3 ++- test/user_counters_tabular_test.cc | 3 ++- test/user_counters_test.cc | 21 ++++++++++++++------- 12 files changed, 51 insertions(+), 46 deletions(-) diff --git a/test/basic_test.cc b/test/basic_test.cc index 80389c2d9e..cba1b0f992 100644 --- a/test/basic_test.cc +++ b/test/basic_test.cc @@ -5,7 +5,8 @@ void BM_empty(benchmark::State& state) { for (auto _ : state) { - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } } BENCHMARK(BM_empty); diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 3e14c4f941..76891e07b4 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -70,7 +70,7 @@ int AddComplexityTest(const std::string &test_name, void BM_Complexity_O1(benchmark::State &state) { for (auto _ : state) { for (int i = 0; i < 1024; ++i) { - benchmark::DoNotOptimize(&i); + benchmark::DoNotOptimize(i); } } state.SetComplexityN(state.range(0)); @@ -121,7 +121,8 @@ void BM_Complexity_O_N(benchmark::State &state) { // Test worst case scenario (item not in vector) const int64_t item_not_in_vector = state.range(0) * 2; for (auto _ : state) { - benchmark::DoNotOptimize(std::find(v.begin(), v.end(), item_not_in_vector)); + auto it = std::find(v.begin(), v.end(), item_not_in_vector); + benchmark::DoNotOptimize(it); } state.SetComplexityN(state.range(0)); } @@ -204,7 +205,8 @@ ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } state.SetComplexityN(n); } diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index c54d5b0d70..fda14b3d57 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -49,7 +49,8 @@ void BM_diagnostic_test(benchmark::State& state) { if (called_once == false) try_invalid_pause_resume(state); for (auto _ : state) { - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } if (called_once == false) try_invalid_pause_resume(state); @@ -64,7 +65,8 @@ void BM_diagnostic_test_keep_running(benchmark::State& state) { if (called_once == false) try_invalid_pause_resume(state); while (state.KeepRunning()) { - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } if (called_once == false) try_invalid_pause_resume(state); diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc index 96881666c9..90d5af35fa 100644 --- a/test/donotoptimize_test.cc +++ b/test/donotoptimize_test.cc @@ -46,36 +46,19 @@ int main(int, char*[]) { char buffer1024[1024] = ""; benchmark::DoNotOptimize(buffer1024); - benchmark::DoNotOptimize(&buffer1024[0]); - - const char const_buffer1[1] = ""; - benchmark::DoNotOptimize(const_buffer1); - - const char const_buffer2[2] = ""; - benchmark::DoNotOptimize(const_buffer2); - - const char const_buffer3[3] = ""; - benchmark::DoNotOptimize(const_buffer3); - - const char const_buffer8[8] = ""; - benchmark::DoNotOptimize(const_buffer8); - - const char const_buffer20[20] = ""; - benchmark::DoNotOptimize(const_buffer20); - - const char const_buffer1024[1024] = ""; - benchmark::DoNotOptimize(const_buffer1024); - benchmark::DoNotOptimize(&const_buffer1024[0]); + char* bptr = &buffer1024[0]; + benchmark::DoNotOptimize(bptr); int x = 123; benchmark::DoNotOptimize(x); - benchmark::DoNotOptimize(&x); + int* xp = &x; + benchmark::DoNotOptimize(xp); benchmark::DoNotOptimize(x += 42); - benchmark::DoNotOptimize(double_up(x)); + std::int64_t y = double_up(x); + benchmark::DoNotOptimize(y); // These tests are to e - benchmark::DoNotOptimize(BitRef::Make()); BitRef lval = BitRef::Make(); benchmark::DoNotOptimize(lval); } diff --git a/test/link_main_test.cc b/test/link_main_test.cc index 241ad5c390..e806500a9a 100644 --- a/test/link_main_test.cc +++ b/test/link_main_test.cc @@ -2,7 +2,8 @@ void BM_empty(benchmark::State& state) { for (auto _ : state) { - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } } BENCHMARK(BM_empty); diff --git a/test/map_test.cc b/test/map_test.cc index 1979fcb829..0fdba7c87c 100644 --- a/test/map_test.cc +++ b/test/map_test.cc @@ -24,7 +24,8 @@ static void BM_MapLookup(benchmark::State& state) { m = ConstructRandomMap(size); state.ResumeTiming(); for (int i = 0; i < size; ++i) { - benchmark::DoNotOptimize(m.find(std::rand() % size)); + auto it = m.find(std::rand() % size); + benchmark::DoNotOptimize(it); } } state.SetItemsProcessed(state.iterations() * size); @@ -47,7 +48,8 @@ BENCHMARK_DEFINE_F(MapFixture, Lookup)(benchmark::State& state) { const int size = static_cast(state.range(0)); for (auto _ : state) { for (int i = 0; i < size; ++i) { - benchmark::DoNotOptimize(m.find(std::rand() % size)); + auto it = m.find(std::rand() % size); + benchmark::DoNotOptimize(it); } } state.SetItemsProcessed(state.iterations() * size); diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index 7cf107fc23..d94bd5161b 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -14,7 +14,8 @@ class TestMemoryManager : public benchmark::MemoryManager { void BM_empty(benchmark::State& state) { for (auto _ : state) { - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } } BENCHMARK(BM_empty); diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index 3017a452fe..f0e9a17156 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -7,7 +7,8 @@ static void BM_Simple(benchmark::State& state) { for (auto _ : state) { - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } } BENCHMARK(BM_Simple); diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 823dca41a1..2eb545a8de 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -93,7 +93,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_basic\",%csv_report$"}}); void BM_bytes_per_second(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } state.SetBytesProcessed(1); } @@ -124,7 +125,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_bytes_per_second\",%csv_bytes_report$"}}); void BM_items_per_second(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } state.SetItemsProcessed(1); } @@ -404,7 +406,8 @@ ADD_CASES(TC_ConsoleOut, {{"^BM_BigArgs/1073741824 %console_report$"}, void BM_Complexity_O1(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } state.SetComplexityN(state.range(0)); } diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 61691ec73e..b8b52457b2 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -141,7 +141,8 @@ ADD_CASES("BM_error_during_running_ranged_for", void BM_error_after_running(benchmark::State& state) { for (auto _ : state) { - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } if (state.thread_index() <= (state.threads() / 2)) state.SkipWithError("error message"); diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index 45ac043d51..c98b769af2 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -372,7 +372,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Tabular/repeats:2/threads:2$", void BM_CounterRates_Tabular(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters.insert({ diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index f4be7ebb32..4cd8ee3739 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -67,7 +67,8 @@ int num_calls1 = 0; void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } state.counters["foo"] = 1; state.counters["bar"] = ++num_calls1; @@ -118,7 +119,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec", void BM_Counters_Rate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters["foo"] = bm::Counter{1, bm::Counter::kIsRate}; @@ -161,7 +163,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate); void BM_Invert(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters["foo"] = bm::Counter{0.0001, bm::Counter::kInvert}; @@ -201,7 +204,8 @@ CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert); void BM_Counters_InvertedRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters["foo"] = @@ -329,7 +333,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int", void BM_Counters_AvgThreadsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreadsRate}; @@ -416,7 +421,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant", void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters["foo"] = @@ -507,7 +513,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations", &CheckAvgIterations); void BM_Counters_kAvgIterationsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - benchmark::DoNotOptimize(state.iterations()); + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterationsRate}; From fbc6efa9b5e138ccb373a6290908d45f85b48945 Mon Sep 17 00:00:00 2001 From: Henrique Bucher <11621271+HFTrader@users.noreply.github.com> Date: Tue, 7 Mar 2023 04:27:52 -0600 Subject: [PATCH 078/561] Refactoring of PerfCounters infrastructure (#1559) * Refactoring of PerfCounters infrastructure The main feature in this pull request is the removal of the static sharing of PerfCounters and instead creating them at the top `RunBenchmarks()` function where all benchmark runners are created. A single PerfCountersMeasurement object is created and then shared with all the new BenchmarkRunners objects, one per existing benchmark. Other features conflated here in this PR are: - Added BENCHMARK_DONT_OPTIMIZE macro in global scope - Removal of the `IsValid()` query, being replaced by checking the number of remaining counters after validity tests - Refactoring of all GTests to reflect the changes and new semantics - extra comments throughout the new code to clarify intent It was extremely hard to separate all those features in different PRs as requested since they are so interdependent on each other so I'm just pushing them altogether and asking for forgiveness. This PR comes replacing PRs 1555 and 1558 which have been closed. * Fixed whitespace issue with clang-format My clang-format insists in deleting this single white space on line 601 while Github's clang format breaks when it is added. I had to disable format-on-save to check-in this revert change. I'm using clang 14.0.6. --- include/benchmark/benchmark.h | 12 +++ src/benchmark.cc | 27 +++++- src/benchmark_runner.cc | 8 +- src/benchmark_runner.h | 4 +- src/perf_counters.cc | 174 +++++++++++++++++----------------- src/perf_counters.h | 39 +++----- test/perf_counters_gtest.cc | 174 ++++++++++++++++++++++------------ 7 files changed, 260 insertions(+), 178 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index c154a15782..ad7c92e914 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -218,6 +218,18 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #define BENCHMARK_UNUSED #endif +// Used to annotate functions, methods and classes so they +// are not optimized by the compiler. Useful for tests +// where you expect loops to stay in place churning cycles +#if defined(__clang__) +#define BENCHMARK_DONT_OPTIMIZE __attribute__((optnone)) +#elif defined(__GNUC__) || defined(__GNUG__) +#define BENCHMARK_DONT_OPTIMIZE __attribute__((optimize(0))) +#else +// MSVC & Intel do not have a no-optimize attribute, only line pragmas +#define BENCHMARK_DONT_OPTIMIZE +#endif + #if defined(__GNUC__) || defined(__clang__) #define BENCHMARK_ALWAYS_INLINE __attribute__((always_inline)) #elif defined(_MSC_VER) && !defined(__clang__) diff --git a/src/benchmark.cc b/src/benchmark.cc index e2d85fe494..b8eda00831 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -348,14 +348,26 @@ void RunBenchmarks(const std::vector& benchmarks, size_t num_repetitions_total = 0; + // This perfcounters object needs to be created before the runners vector + // below so it outlasts their lifetime. + PerfCountersMeasurement perfcounters( + StrSplit(FLAGS_benchmark_perf_counters, ',')); + + // Vector of benchmarks to run std::vector runners; runners.reserve(benchmarks.size()); + + // Count the number of benchmarks with threads to warn the user in case + // performance counters are used. + int benchmarks_with_threads = 0; + + // Loop through all benchmarks for (const BenchmarkInstance& benchmark : benchmarks) { BenchmarkReporter::PerFamilyRunReports* reports_for_family = nullptr; if (benchmark.complexity() != oNone) reports_for_family = &per_family_reports[benchmark.family_index()]; - - runners.emplace_back(benchmark, reports_for_family); + benchmarks_with_threads += (benchmark.threads() > 0); + runners.emplace_back(benchmark, &perfcounters, reports_for_family); int num_repeats_of_this_instance = runners.back().GetNumRepeats(); num_repetitions_total += num_repeats_of_this_instance; if (reports_for_family) @@ -363,6 +375,17 @@ void RunBenchmarks(const std::vector& benchmarks, } assert(runners.size() == benchmarks.size() && "Unexpected runner count."); + // The use of performance counters with threads would be unintuitive for + // the average user so we need to warn them about this case + if ((benchmarks_with_threads > 0) && (perfcounters.num_counters() > 0)) { + GetErrorLogInstance() + << "***WARNING*** There are " << benchmarks_with_threads + << " benchmarks with threads and " << perfcounters.num_counters() + << " performance counters were requested. Beware counters will " + "reflect the combined usage across all " + "threads.\n"; + } + std::vector repetition_indices; repetition_indices.reserve(num_repetitions_total); for (size_t runner_index = 0, num_runners = runners.size(); diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 09975a9eb6..58147ca7e6 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -221,6 +221,7 @@ BenchTimeType ParseBenchMinTime(const std::string& value) { BenchmarkRunner::BenchmarkRunner( const benchmark::internal::BenchmarkInstance& b_, + PerfCountersMeasurement* pcm_, BenchmarkReporter::PerFamilyRunReports* reports_for_family_) : b(b_), reports_for_family(reports_for_family_), @@ -239,10 +240,7 @@ BenchmarkRunner::BenchmarkRunner( iters(has_explicit_iteration_count ? ComputeIters(b_, parsed_benchtime_flag) : 1), - perf_counters_measurement(StrSplit(FLAGS_benchmark_perf_counters, ',')), - perf_counters_measurement_ptr(perf_counters_measurement.IsValid() - ? &perf_counters_measurement - : nullptr) { + perf_counters_measurement_ptr(pcm_) { run_results.display_report_aggregates_only = (FLAGS_benchmark_report_aggregates_only || FLAGS_benchmark_display_aggregates_only); @@ -255,7 +253,7 @@ BenchmarkRunner::BenchmarkRunner( run_results.file_report_aggregates_only = (b.aggregation_report_mode() & internal::ARM_FileReportAggregatesOnly); BM_CHECK(FLAGS_benchmark_perf_counters.empty() || - perf_counters_measurement.IsValid()) + (perf_counters_measurement_ptr->num_counters() == 0)) << "Perf counters were requested but could not be set up."; } } diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index 9d80653728..db2fa04396 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -58,6 +58,7 @@ BenchTimeType ParseBenchMinTime(const std::string& value); class BenchmarkRunner { public: BenchmarkRunner(const benchmark::internal::BenchmarkInstance& b_, + benchmark::internal::PerfCountersMeasurement* pmc_, BenchmarkReporter::PerFamilyRunReports* reports_for_family); int GetNumRepeats() const { return repeats; } @@ -103,8 +104,7 @@ class BenchmarkRunner { // So only the first repetition has to find/calculate it, // the other repetitions will just use that precomputed iteration count. - PerfCountersMeasurement perf_counters_measurement; - PerfCountersMeasurement* const perf_counters_measurement_ptr; + PerfCountersMeasurement* const perf_counters_measurement_ptr = nullptr; struct IterationResults { internal::ThreadManager::Result results; diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 38b73ae41b..3980ea053e 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -71,80 +71,78 @@ bool PerfCounters::IsCounterSupported(const std::string& name) { return (ret == PFM_SUCCESS); } -// Validates all counter names passed, returning only the valid ones -static std::vector validateCounters( +PerfCounters PerfCounters::Create( const std::vector& counter_names) { - // All valid names to be returned + // Valid counters will populate these arrays but we start empty std::vector valid_names; + std::vector counter_ids; + std::vector leader_ids; + + // Resize to the maximum possible + valid_names.reserve(counter_names.size()); + counter_ids.reserve(counter_names.size()); + + const int kCounterMode = PFM_PLM3; // user mode only + + // Group leads will be assigned on demand. The idea is that once we cannot + // create a counter descriptor, the reason is that this group has maxed out + // so we set the group_id again to -1 and retry - giving the algorithm a + // chance to create a new group leader to hold the next set of counters. + int group_id = -1; - // Loop through all the given names - int invalid_counter = 0; - for (const std::string& name : counter_names) { - // Check trivial empty + // Loop through all performance counters + for (size_t i = 0; i < counter_names.size(); ++i) { + // we are about to push into the valid names vector + // check if we did not reach the maximum + if (valid_names.size() == PerfCounterValues::kMaxCounters) { + // Log a message if we maxed out and stop adding + GetErrorLogInstance() + << counter_names.size() << " counters were requested. The maximum is " + << PerfCounterValues::kMaxCounters << " and " << valid_names.size() + << " were already added. All remaining counters will be ignored\n"; + // stop the loop and return what we have already + break; + } + + // Check if this name is empty + const auto& name = counter_names[i]; if (name.empty()) { - GetErrorLogInstance() << "A counter name was the empty string\n"; - invalid_counter++; + GetErrorLogInstance() + << "A performance counter name was the empty string\n"; continue; } - if (PerfCounters::IsCounterSupported(name)) { - // we are about to push into the valid names vector - // check if we did not reach the maximum - if (valid_names.size() == PerfCounterValues::kMaxCounters) { - GetErrorLogInstance() - << counter_names.size() - << " counters were requested. The maximum is " - << PerfCounterValues::kMaxCounters << " and " - << counter_names.size() - invalid_counter - valid_names.size() - << " will be ignored\n"; - // stop the loop and return what we have already - break; - } - valid_names.push_back(name); - } else { - GetErrorLogInstance() << "Performance counter " << name - << " incorrect or not supported on this platform\n"; - invalid_counter++; - } - } - // RVO should take care of this - return valid_names; -} - -PerfCounters PerfCounters::Create( - const std::vector& counter_names) { - std::vector valid_names = validateCounters(counter_names); - if (valid_names.empty()) { - return NoCounters(); - } - std::vector counter_ids(valid_names.size()); - std::vector leader_ids; - const int mode = PFM_PLM3; // user mode only - int group_id = -1; - for (size_t i = 0; i < valid_names.size(); ++i) { + // Here first means first in group, ie the group leader const bool is_first = (group_id < 0); + + // This struct will be populated by libpfm from the counter string + // and then fed into the syscall perf_event_open struct perf_event_attr attr {}; attr.size = sizeof(attr); - const auto& name = valid_names[i]; + + // This is the input struct to libpfm. pfm_perf_encode_arg_t arg{}; arg.attr = &attr; - - const int pfm_get = - pfm_get_os_event_encoding(name.c_str(), mode, PFM_OS_PERF_EVENT, &arg); + const int pfm_get = pfm_get_os_event_encoding(name.c_str(), kCounterMode, + PFM_OS_PERF_EVENT, &arg); if (pfm_get != PFM_SUCCESS) { - GetErrorLogInstance() << "Unknown counter name: " << name << "\n"; - return NoCounters(); + GetErrorLogInstance() + << "Unknown performance counter name: " << name << "\n"; + continue; } - attr.disabled = is_first; + + // We then proceed to populate the remaining fields in our attribute struct // Note: the man page for perf_event_create suggests inherit = true and // read_format = PERF_FORMAT_GROUP don't work together, but that's not the // case. + attr.disabled = is_first; attr.inherit = true; attr.pinned = is_first; attr.exclude_kernel = true; attr.exclude_user = false; attr.exclude_hv = true; - // Read all counters in one read. + + // Read all counters in a group in one read. attr.read_format = PERF_FORMAT_GROUP; int id = -1; @@ -159,36 +157,64 @@ PerfCounters PerfCounters::Create( } } if (id < 0) { - // We reached a limit perhaps? + // If the file descriptor is negative we might have reached a limit + // in the current group. Set the group_id to -1 and retry if (group_id >= 0) { // Create a new group group_id = -1; } else { - // Give up, there is nothing else to try + // At this point we have already retried to set a new group id and + // failed. We then give up. break; } } } + + // We failed to get a new file descriptor. We might have reached a hard + // hardware limit that cannot be resolved even with group multiplexing if (id < 0) { - GetErrorLogInstance() - << "Failed to get a file descriptor for " << name << "\n"; - return NoCounters(); + GetErrorLogInstance() << "***WARNING** Failed to get a file descriptor " + "for performance counter " + << name << ". Ignoring\n"; + + // We give up on this counter but try to keep going + // as the others would be fine + continue; } if (group_id < 0) { - // This is a leader, store and assign it + // This is a leader, store and assign it to the current file descriptor leader_ids.push_back(id); group_id = id; } - counter_ids[i] = id; + // This is a valid counter, add it to our descriptor's list + counter_ids.push_back(id); + valid_names.push_back(name); } + + // Loop through all group leaders activating them + // There is another option of starting ALL counters in a process but + // that would be far reaching an intrusion. If the user is using PMCs + // by themselves then this would have a side effect on them. It is + // friendlier to loop through all groups individually. for (int lead : leader_ids) { if (ioctl(lead, PERF_EVENT_IOC_ENABLE) != 0) { - GetErrorLogInstance() << "Failed to start counters\n"; + // This should never happen but if it does, we give up on the + // entire batch as recovery would be a mess. + GetErrorLogInstance() << "***WARNING*** Failed to start counters. " + "Claring out all counters.\n"; + + // Close all peformance counters + for (int id : counter_ids) { + ::close(id); + } + + // Return an empty object so our internal state is still good and + // the process can continue normally without impact return NoCounters(); } } - return PerfCounters(valid_names, std::move(counter_ids), + return PerfCounters(std::move(valid_names), std::move(counter_ids), std::move(leader_ids)); } @@ -223,34 +249,10 @@ PerfCounters PerfCounters::Create( void PerfCounters::CloseCounters() const {} #endif // defined HAVE_LIBPFM -Mutex PerfCountersMeasurement::mutex_; -int PerfCountersMeasurement::ref_count_ = 0; -PerfCounters PerfCountersMeasurement::counters_ = PerfCounters::NoCounters(); - -// The validation in PerfCounter::Create will create less counters than passed -// so it should be okay to initialize start_values_ and end_values_ with the -// upper bound as passed PerfCountersMeasurement::PerfCountersMeasurement( const std::vector& counter_names) : start_values_(counter_names.size()), end_values_(counter_names.size()) { - MutexLock l(mutex_); - if (ref_count_ == 0) { - counters_ = PerfCounters::Create(counter_names); - } - // We chose to increment it even if `counters_` ends up invalid, - // so that we don't keep trying to create, and also since the dtor - // will decrement regardless of `counters_`'s validity - ++ref_count_; - - BM_CHECK(!counters_.IsValid() || counters_.names() == counter_names); -} - -PerfCountersMeasurement::~PerfCountersMeasurement() { - MutexLock l(mutex_); - --ref_count_; - if (ref_count_ == 0) { - counters_ = PerfCounters::NoCounters(); - } + counters_ = PerfCounters::Create(counter_names); } PerfCounters& PerfCounters::operator=(PerfCounters&& other) noexcept { diff --git a/src/perf_counters.h b/src/perf_counters.h index aeea350d7f..152a6f2561 100644 --- a/src/perf_counters.h +++ b/src/perf_counters.h @@ -90,10 +90,11 @@ class BENCHMARK_EXPORT PerfCounters final { // True iff this platform supports performance counters. static const bool kSupported; - bool IsValid() const { return !counter_names_.empty(); } + // Returns an empty object static PerfCounters NoCounters() { return PerfCounters(); } ~PerfCounters() { CloseCounters(); } + PerfCounters() = default; PerfCounters(PerfCounters&&) = default; PerfCounters(const PerfCounters&) = delete; PerfCounters& operator=(PerfCounters&&) noexcept; @@ -110,8 +111,8 @@ class BENCHMARK_EXPORT PerfCounters final { // Return a PerfCounters object ready to read the counters with the names // specified. The values are user-mode only. The counter name format is // implementation and OS specific. - // TODO: once we move to C++-17, this should be a std::optional, and then the - // IsValid() boolean can be dropped. + // In case of failure, this method will in the worst case return an + // empty object whose state will still be valid. static PerfCounters Create(const std::vector& counter_names); // Take a snapshot of the current value of the counters into the provided @@ -120,7 +121,6 @@ class BENCHMARK_EXPORT PerfCounters final { BENCHMARK_ALWAYS_INLINE bool Snapshot(PerfCounterValues* values) const { #ifndef BENCHMARK_OS_WINDOWS assert(values != nullptr); - assert(IsValid()); return values->Read(leader_ids_) == counter_ids_.size(); #else (void)values; @@ -137,7 +137,6 @@ class BENCHMARK_EXPORT PerfCounters final { : counter_ids_(std::move(counter_ids)), leader_ids_(std::move(leader_ids)), counter_names_(counter_names) {} - PerfCounters() = default; void CloseCounters() const; @@ -150,33 +149,25 @@ class BENCHMARK_EXPORT PerfCounters final { class BENCHMARK_EXPORT PerfCountersMeasurement final { public: PerfCountersMeasurement(const std::vector& counter_names); - ~PerfCountersMeasurement(); - - // The only way to get to `counters_` is after ctor-ing a - // `PerfCountersMeasurement`, which means that `counters_`'s state is, here, - // decided (either invalid or valid) and won't change again even if a ctor is - // concurrently running with this. This is preferring efficiency to - // maintainability, because the address of the static can be known at compile - // time. - bool IsValid() const { - MutexLock l(mutex_); - return counters_.IsValid(); - } - BENCHMARK_ALWAYS_INLINE void Start() { - assert(IsValid()); - MutexLock l(mutex_); + size_t num_counters() const { return counters_.num_counters(); } + + std::vector names() const { return counters_.names(); } + + BENCHMARK_ALWAYS_INLINE bool Start() { + if (num_counters() == 0) return true; // Tell the compiler to not move instructions above/below where we take // the snapshot. ClobberMemory(); valid_read_ &= counters_.Snapshot(&start_values_); ClobberMemory(); + + return valid_read_; } BENCHMARK_ALWAYS_INLINE bool Stop( std::vector>& measurements) { - assert(IsValid()); - MutexLock l(mutex_); + if (num_counters() == 0) return true; // Tell the compiler to not move instructions above/below where we take // the snapshot. ClobberMemory(); @@ -193,9 +184,7 @@ class BENCHMARK_EXPORT PerfCountersMeasurement final { } private: - static Mutex mutex_; - GUARDED_BY(mutex_) static int ref_count_; - GUARDED_BY(mutex_) static PerfCounters counters_; + PerfCounters counters_; bool valid_read_ = true; PerfCounterValues start_values_; PerfCounterValues end_values_; diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index e31758def5..e73ebc5886 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -1,3 +1,4 @@ +#include #include #include "../src/perf_counters.h" @@ -28,7 +29,7 @@ TEST(PerfCountersTest, OneCounter) { GTEST_SKIP() << "Performance counters not supported.\n"; } EXPECT_TRUE(PerfCounters::Initialize()); - EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1}).IsValid()); + EXPECT_EQ(PerfCounters::Create({kGenericPerfEvent1}).num_counters(), 1); } TEST(PerfCountersTest, NegativeTest) { @@ -37,38 +38,42 @@ TEST(PerfCountersTest, NegativeTest) { return; } EXPECT_TRUE(PerfCounters::Initialize()); - EXPECT_FALSE(PerfCounters::Create({}).IsValid()); - EXPECT_FALSE(PerfCounters::Create({""}).IsValid()); - EXPECT_FALSE(PerfCounters::Create({"not a counter name"}).IsValid()); - EXPECT_TRUE(PerfCounters::Create( - {kGenericPerfEvent1, kGenericPerfEvent2, kGenericPerfEvent3}) - .IsValid()); + // Sanity checks + // Create() will always create a valid object, even if passed no or + // wrong arguments as the new behavior is to warn and drop unsupported + // counters + EXPECT_EQ(PerfCounters::Create({}).num_counters(), 0); + EXPECT_EQ(PerfCounters::Create({""}).num_counters(), 0); + EXPECT_EQ(PerfCounters::Create({"not a counter name"}).num_counters(), 0); { + // Try sneaking in a bad egg to see if it is filtered out. The + // number of counters has to be two, not zero auto counter = PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1}); - EXPECT_TRUE(counter.IsValid()); EXPECT_EQ(counter.num_counters(), 2); EXPECT_EQ(counter.names(), std::vector( {kGenericPerfEvent2, kGenericPerfEvent1})); } { + // Try sneaking in an outrageous counter, like a fat finger mistake auto counter = PerfCounters::Create( {kGenericPerfEvent3, "not a counter name", kGenericPerfEvent1}); - EXPECT_TRUE(counter.IsValid()); EXPECT_EQ(counter.num_counters(), 2); EXPECT_EQ(counter.names(), std::vector( {kGenericPerfEvent3, kGenericPerfEvent1})); } { - EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, - kGenericPerfEvent3}) - .IsValid()); + // Finally try a golden input - it should like all them + EXPECT_EQ(PerfCounters::Create( + {kGenericPerfEvent1, kGenericPerfEvent2, kGenericPerfEvent3}) + .num_counters(), + 3); } { + // Add a bad apple in the end of the chain to check the edges auto counter = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, kGenericPerfEvent3, "MISPREDICTED_BRANCH_RETIRED"}); - EXPECT_TRUE(counter.IsValid()); EXPECT_EQ(counter.num_counters(), 3); EXPECT_EQ(counter.names(), std::vector({kGenericPerfEvent1, kGenericPerfEvent2, @@ -82,7 +87,7 @@ TEST(PerfCountersTest, Read1Counter) { } EXPECT_TRUE(PerfCounters::Initialize()); auto counters = PerfCounters::Create({kGenericPerfEvent1}); - EXPECT_TRUE(counters.IsValid()); + EXPECT_EQ(counters.num_counters(), 1); PerfCounterValues values1(1); EXPECT_TRUE(counters.Snapshot(&values1)); EXPECT_GT(values1[0], 0); @@ -99,7 +104,7 @@ TEST(PerfCountersTest, Read2Counters) { EXPECT_TRUE(PerfCounters::Initialize()); auto counters = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}); - EXPECT_TRUE(counters.IsValid()); + EXPECT_EQ(counters.num_counters(), 2); PerfCounterValues values1(2); EXPECT_TRUE(counters.Snapshot(&values1)); EXPECT_GT(values1[0], 0); @@ -111,62 +116,107 @@ TEST(PerfCountersTest, Read2Counters) { } TEST(PerfCountersTest, ReopenExistingCounters) { - // The test works (i.e. causes read to fail) for the assumptions - // about hardware capabilities (i.e. small number (3-4) hardware - // counters) at this date. + // This test works in recent and old Intel hardware + // However we cannot make assumptions beyond 3 HW counters if (!PerfCounters::kSupported) { GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; } EXPECT_TRUE(PerfCounters::Initialize()); - std::vector counters; - counters.reserve(6); - for (int i = 0; i < 6; i++) - counters.push_back(PerfCounters::Create({kGenericPerfEvent1})); + std::vector kMetrics({kGenericPerfEvent1}); + std::vector counters(3); + for (auto& counter : counters) { + counter = PerfCounters::Create(kMetrics); + } PerfCounterValues values(1); EXPECT_TRUE(counters[0].Snapshot(&values)); - EXPECT_FALSE(counters[4].Snapshot(&values)); - EXPECT_FALSE(counters[5].Snapshot(&values)); + EXPECT_TRUE(counters[1].Snapshot(&values)); + EXPECT_TRUE(counters[2].Snapshot(&values)); } TEST(PerfCountersTest, CreateExistingMeasurements) { // The test works (i.e. causes read to fail) for the assumptions - // about hardware capabilities (i.e. small number (3-4) hardware + // about hardware capabilities (i.e. small number (3) hardware // counters) at this date, // the same as previous test ReopenExistingCounters. if (!PerfCounters::kSupported) { GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; } EXPECT_TRUE(PerfCounters::Initialize()); - std::vector perf_counter_measurements; - std::vector> measurements; - perf_counter_measurements.reserve(10); - for (int i = 0; i < 10; i++) + // This means we will try 10 counters but we can only guarantee + // for sure at this time that only 3 will work. Perhaps in the future + // we could use libpfm to query for the hardware limits on this + // particular platform. + const int kMaxCounters = 10; + const int kMinValidCounters = 3; + + // Let's use a ubiquitous counter that is guaranteed to work + // on all platforms + const std::vector kMetrics{"cycles"}; + + // Cannot create a vector of actual objects because the + // copy constructor of PerfCounters is deleted - and so is + // implicitly deleted on PerfCountersMeasurement too + std::vector> + perf_counter_measurements; + + perf_counter_measurements.reserve(kMaxCounters); + for (int j = 0; j < kMaxCounters; ++j) { perf_counter_measurements.emplace_back( - std::vector{kGenericPerfEvent1}); + new PerfCountersMeasurement(kMetrics)); + } - perf_counter_measurements[0].Start(); - EXPECT_TRUE(perf_counter_measurements[0].Stop(measurements)); + std::vector> measurements; + + // Start all counters together to see if they hold + int max_counters = kMaxCounters; + for (int i = 0; i < kMaxCounters; ++i) { + auto& counter(*perf_counter_measurements[i]); + EXPECT_EQ(counter.num_counters(), 1); + if (!counter.Start()) { + max_counters = i; + break; + }; + } - measurements.clear(); - perf_counter_measurements[8].Start(); - EXPECT_FALSE(perf_counter_measurements[8].Stop(measurements)); + ASSERT_GE(max_counters, kMinValidCounters); + + // Start all together + for (int i = 0; i < max_counters; ++i) { + auto& counter(*perf_counter_measurements[i]); + EXPECT_TRUE(counter.Stop(measurements) || (i >= kMinValidCounters)); + } - measurements.clear(); - perf_counter_measurements[9].Start(); - EXPECT_FALSE(perf_counter_measurements[9].Stop(measurements)); + // Start/stop individually + for (int i = 0; i < max_counters; ++i) { + auto& counter(*perf_counter_measurements[i]); + measurements.clear(); + counter.Start(); + EXPECT_TRUE(counter.Stop(measurements) || (i >= kMinValidCounters)); + } } -size_t do_work() { - size_t res = 0; - for (size_t i = 0; i < 100000000; ++i) res += i * i; - return res; +// We try to do some meaningful work here but the compiler +// insists in optimizing away our loop so we had to add a +// no-optimize macro. In case it fails, we added some entropy +// to this pool as well. + +BENCHMARK_DONT_OPTIMIZE size_t do_work() { + static std::mt19937 rd{std::random_device{}()}; + static std::uniform_int_distribution mrand(0, 10); + const size_t kNumLoops = 1000000; + size_t sum = 0; + for (size_t j = 0; j < kNumLoops; ++j) { + sum += mrand(rd); + } + benchmark::DoNotOptimize(sum); + return sum; } -void measure(size_t threadcount, PerfCounterValues* values1, - PerfCounterValues* values2) { - BM_CHECK_NE(values1, nullptr); - BM_CHECK_NE(values2, nullptr); +void measure(size_t threadcount, PerfCounterValues* before, + PerfCounterValues* after) { + BM_CHECK_NE(before, nullptr); + BM_CHECK_NE(after, nullptr); std::vector threads(threadcount); auto work = [&]() { BM_CHECK(do_work() > 1000); }; @@ -178,9 +228,9 @@ void measure(size_t threadcount, PerfCounterValues* values1, auto counters = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent3}); for (auto& t : threads) t = std::thread(work); - counters.Snapshot(values1); + counters.Snapshot(before); for (auto& t : threads) t.join(); - counters.Snapshot(values2); + counters.Snapshot(after); } TEST(PerfCountersTest, MultiThreaded) { @@ -188,21 +238,29 @@ TEST(PerfCountersTest, MultiThreaded) { GTEST_SKIP() << "Test skipped because libpfm is not supported."; } EXPECT_TRUE(PerfCounters::Initialize()); - PerfCounterValues values1(2); - PerfCounterValues values2(2); + PerfCounterValues before(2); + PerfCounterValues after(2); - measure(2, &values1, &values2); - std::vector D1{static_cast(values2[0] - values1[0]), - static_cast(values2[1] - values1[1])}; + // Notice that this test will work even if we taskset it to a single CPU + // In this case the threads will run sequentially + // Start two threads and measure the number of combined cycles and + // instructions + measure(2, &before, &after); + std::vector Elapsed2Threads{ + static_cast(after[0] - before[0]), + static_cast(after[1] - before[1])}; - measure(4, &values1, &values2); - std::vector D2{static_cast(values2[0] - values1[0]), - static_cast(values2[1] - values1[1])}; + // Start four threads and measure the number of combined cycles and + // instructions + measure(4, &before, &after); + std::vector Elapsed4Threads{ + static_cast(after[0] - before[0]), + static_cast(after[1] - before[1])}; // Some extra work will happen on the main thread - like joining the threads // - so the ratio won't be quite 2.0, but very close. - EXPECT_GE(D2[0], 1.9 * D1[0]); - EXPECT_GE(D2[1], 1.9 * D1[1]); + EXPECT_GE(Elapsed4Threads[0], 1.9 * Elapsed2Threads[0]); + EXPECT_GE(Elapsed4Threads[1], 1.9 * Elapsed2Threads[1]); } TEST(PerfCountersTest, HardwareLimits) { From 23dadfa4a7812c9ee16812e3b6eff05c57a30745 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 7 Mar 2023 12:22:00 +0100 Subject: [PATCH 079/561] Bump nanobind to stable v0.2.0, change linker options (#1565) Bumps nanobind to v0.2.0, the latest stable version to include all features needed to create the GBM bindings. Deprecated names in v0.2.0 were migrated to their new counterparts. Linkopts for macOS were changed to mirror the "endorsed" linker options used in nanobind's CMake config, which were changed since the last commit. --- bazel/benchmark_deps.bzl | 3 ++- bindings/python/google_benchmark/benchmark.cc | 26 +++++++++---------- bindings/python/nanobind.BUILD | 8 ++++-- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 8c786fbc28..bc1fc9f1ea 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -48,7 +48,8 @@ def benchmark_deps(): git_repository( name = "nanobind", remote = "https://github.com/wjakob/nanobind.git", - commit = "fe3ecb800a7a3e8023e8ee77167a6241591e0b8b", + commit = "1ffbfe836c9dac599496a170274ee0075094a607", # v0.2.0 + shallow_since = "1677873085 +0100", build_file = "@//bindings/python:nanobind.BUILD", recursive_init_submodules = True, ) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index 991da5a5aa..cf2da2e812 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -142,9 +142,9 @@ NB_MODULE(_benchmark, m) { nb::arg("value") = 0., nb::arg("flags") = Counter::kDefaults, nb::arg("k") = Counter::kIs1000) .def("__init__", ([](Counter *c, double value) { new (c) Counter(value); })) - .def_readwrite("value", &Counter::value) - .def_readwrite("flags", &Counter::flags) - .def_readwrite("oneK", &Counter::oneK) + .def_rw("value", &Counter::value) + .def_rw("flags", &Counter::flags) + .def_rw("oneK", &Counter::oneK) .def(nb::init_implicit()); nb::implicitly_convertible(); @@ -154,25 +154,25 @@ NB_MODULE(_benchmark, m) { using benchmark::State; nb::class_(m, "State") .def("__bool__", &State::KeepRunning) - .def_property_readonly("keep_running", &State::KeepRunning) + .def_prop_ro("keep_running", &State::KeepRunning) .def("pause_timing", &State::PauseTiming) .def("resume_timing", &State::ResumeTiming) .def("skip_with_error", &State::SkipWithError) - .def_property_readonly("error_occurred", &State::error_occurred) + .def_prop_ro("error_occurred", &State::error_occurred) .def("set_iteration_time", &State::SetIterationTime) - .def_property("bytes_processed", &State::bytes_processed, + .def_prop_rw("bytes_processed", &State::bytes_processed, &State::SetBytesProcessed) - .def_property("complexity_n", &State::complexity_length_n, + .def_prop_rw("complexity_n", &State::complexity_length_n, &State::SetComplexityN) - .def_property("items_processed", &State::items_processed, + .def_prop_rw("items_processed", &State::items_processed, &State::SetItemsProcessed) .def("set_label", (void (State::*)(const char*)) & State::SetLabel) .def("range", &State::range, nb::arg("pos") = 0) - .def_property_readonly("iterations", &State::iterations) - .def_property_readonly("name", &State::name) - .def_readwrite("counters", &State::counters) - .def_property_readonly("thread_index", &State::thread_index) - .def_property_readonly("threads", &State::threads); + .def_prop_ro("iterations", &State::iterations) + .def_prop_ro("name", &State::name) + .def_rw("counters", &State::counters) + .def_prop_ro("thread_index", &State::thread_index) + .def_prop_ro("threads", &State::threads); m.def("Initialize", Initialize); m.def("RegisterBenchmark", RegisterBenchmark, diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD index 9a8d6a041b..35536bba21 100644 --- a/bindings/python/nanobind.BUILD +++ b/bindings/python/nanobind.BUILD @@ -30,8 +30,8 @@ cc_library( "src/nb_func.cpp", "src/nb_internals.cpp", "src/nb_internals.h", + "src/nb_ndarray.cpp", "src/nb_type.cpp", - "src/tensor.cpp", "src/trampoline.cpp", ], copts = select({ @@ -43,7 +43,11 @@ cc_library( ], }), linkopts = select({ - "@com_github_google_benchmark//:macos": ["-undefined suppress", "-flat_namespace"], + "@com_github_google_benchmark//:macos": [ + "-undefined dynamic_lookup", + "-Wl,-no_fixup_chains", + "-Wl,-dead_strip", + ], "//conditions:default": [], }), includes = ["include", "ext/robin_map/include"], From f23fedbbf8a581a42b0e480d754f2183cd58d3e9 Mon Sep 17 00:00:00 2001 From: Marcel Jacobse <44684927+mjacobse@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:47:03 +0100 Subject: [PATCH 080/561] Fix examples in user guide using deprecated `DoNotOptimize`-API (#1568) * Update AUTHORS/CONTRIBUTORS * Fix examples with deprecated DoNotOptimize API The const-reference API to DoNotOptimize was deprecated with #1493. Some examples in the user guide are using exactly that deprecated interface. This fixes that by passing non-const lvalues instead. Fixes #1566 --- AUTHORS | 1 + CONTRIBUTORS | 1 + docs/user_guide.md | 9 ++++++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 205951bcec..b7b3b2e493 100644 --- a/AUTHORS +++ b/AUTHORS @@ -43,6 +43,7 @@ Jussi Knuuttila Kaito Udagawa Kishan Kumar Lei Xu +Marcel Jacobse Matt Clarkson Maxim Vafin MongoDB Inc. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 10243a563f..37b000a19f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -64,6 +64,7 @@ Kai Wolf Kaito Udagawa Kishan Kumar Lei Xu +Marcel Jacobse Matt Clarkson Maxim Vafin Nick Hutchinson diff --git a/docs/user_guide.md b/docs/user_guide.md index fbd29b9aae..7fffb60364 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -346,7 +346,8 @@ the performance of `std::vector` initialization for uniformly increasing sizes. static void BM_DenseRange(benchmark::State& state) { for(auto _ : state) { std::vector v(state.range(0), state.range(0)); - benchmark::DoNotOptimize(v.data()); + auto data = v.data(); + benchmark::DoNotOptimize(data); benchmark::ClobberMemory(); } } @@ -492,7 +493,8 @@ static void BM_StringCompare(benchmark::State& state) { std::string s1(state.range(0), '-'); std::string s2(state.range(0), '-'); for (auto _ : state) { - benchmark::DoNotOptimize(s1.compare(s2)); + auto comparison_result = s1.compare(s2); + benchmark::DoNotOptimize(comparison_result); } state.SetComplexityN(state.range(0)); } @@ -1005,7 +1007,8 @@ static void BM_vector_push_back(benchmark::State& state) { for (auto _ : state) { std::vector v; v.reserve(1); - benchmark::DoNotOptimize(v.data()); // Allow v.data() to be clobbered. + auto data = v.data(); // Allow v.data() to be clobbered. Pass as non-const + benchmark::DoNotOptimize(data); // lvalue to avoid undesired compiler optimizations v.push_back(42); benchmark::ClobberMemory(); // Force 42 to be written to memory. } From 4050b4bda5a3dd479901c44427032101eeb0dfa6 Mon Sep 17 00:00:00 2001 From: Henrique Bucher <11621271+HFTrader@users.noreply.github.com> Date: Wed, 8 Mar 2023 03:50:30 -0600 Subject: [PATCH 081/561] Fix build break with nvc++ when -Werror is ON (#1569) Build breaks when -Werror is turned on because of unhandled cases of inocuous/pedantic warnings. Adopted the same solution as for Intel PGI compiler - just disable -Werror manually, unless BENCHMARK_FORCE_WERROR is enabled. Fixes #1556. --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e7701e32d..5442bf768a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,9 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "PGI") # PGC++ maybe reporting false positives. set(BENCHMARK_ENABLE_WERROR OFF) endif() +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "NVHPC") + set(BENCHMARK_ENABLE_WERROR OFF) +endif() if(BENCHMARK_FORCE_WERROR) set(BENCHMARK_ENABLE_WERROR ON) endif(BENCHMARK_FORCE_WERROR) From adb0d3d0bf5841bddc2bcc025baad93dbc7fa39f Mon Sep 17 00:00:00 2001 From: Mike Apodaca Date: Wed, 8 Mar 2023 10:24:48 -0800 Subject: [PATCH 082/561] [FR] state.SkipWithMessage #963 (#1564) * Add `SkipWithMessage` * Added `enum Skipped` * Fix: error at end of enumerator list * Fix lint errors --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- include/benchmark/benchmark.h | 61 +++++++++++++++++++++++++++-------- src/benchmark.cc | 41 +++++++++++++++-------- src/benchmark_runner.cc | 12 +++---- src/console_reporter.cc | 8 +++-- src/csv_reporter.cc | 6 ++-- src/json_reporter.cc | 9 ++++-- src/statistics.cc | 7 ++-- src/thread_manager.h | 4 +-- test/skip_with_error_test.cc | 5 +-- 9 files changed, 104 insertions(+), 49 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index ad7c92e914..bb29c73d31 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -667,6 +667,16 @@ enum AggregationReportMode ARM_FileReportAggregatesOnly | ARM_DisplayReportAggregatesOnly }; +enum Skipped +#if defined(BENCHMARK_HAS_CXX11) + : unsigned +#endif +{ + NotSkipped = 0, + SkippedWithMessage, + SkippedWithError +}; + } // namespace internal // State is passed to a running Benchmark and contains state for the @@ -703,8 +713,8 @@ class BENCHMARK_EXPORT State { // } bool KeepRunningBatch(IterationCount n); - // REQUIRES: timer is running and 'SkipWithError(...)' has not been called - // by the current thread. + // REQUIRES: timer is running and 'SkipWithMessage(...)' or + // 'SkipWithError(...)' has not been called by the current thread. // Stop the benchmark timer. If not called, the timer will be // automatically stopped after the last iteration of the benchmark loop. // @@ -719,8 +729,8 @@ class BENCHMARK_EXPORT State { // within each benchmark iteration, if possible. void PauseTiming(); - // REQUIRES: timer is not running and 'SkipWithError(...)' has not been called - // by the current thread. + // REQUIRES: timer is not running and 'SkipWithMessage(...)' or + // 'SkipWithError(...)' has not been called by the current thread. // Start the benchmark timer. The timer is NOT running on entrance to the // benchmark function. It begins running after control flow enters the // benchmark loop. @@ -730,8 +740,30 @@ class BENCHMARK_EXPORT State { // within each benchmark iteration, if possible. void ResumeTiming(); - // REQUIRES: 'SkipWithError(...)' has not been called previously by the - // current thread. + // REQUIRES: 'SkipWithMessage(...)' or 'SkipWithError(...)' has not been + // called previously by the current thread. + // Report the benchmark as resulting in being skipped with the specified + // 'msg'. + // After this call the user may explicitly 'return' from the benchmark. + // + // If the ranged-for style of benchmark loop is used, the user must explicitly + // break from the loop, otherwise all future iterations will be run. + // If the 'KeepRunning()' loop is used the current thread will automatically + // exit the loop at the end of the current iteration. + // + // For threaded benchmarks only the current thread stops executing and future + // calls to `KeepRunning()` will block until all threads have completed + // the `KeepRunning()` loop. If multiple threads report being skipped only the + // first skip message is used. + // + // NOTE: Calling 'SkipWithMessage(...)' does not cause the benchmark to exit + // the current scope immediately. If the function is called from within + // the 'KeepRunning()' loop the current iteration will finish. It is the users + // responsibility to exit the scope as needed. + void SkipWithMessage(const char* msg); + + // REQUIRES: 'SkipWithMessage(...)' or 'SkipWithError(...)' has not been + // called previously by the current thread. // Report the benchmark as resulting in an error with the specified 'msg'. // After this call the user may explicitly 'return' from the benchmark. // @@ -751,8 +783,11 @@ class BENCHMARK_EXPORT State { // responsibility to exit the scope as needed. void SkipWithError(const char* msg); + // Returns true if 'SkipWithMessage(...)' or 'SkipWithError(...)' was called. + bool skipped() const { return internal::NotSkipped != skipped_; } + // Returns true if an error has been reported with 'SkipWithError(...)'. - bool error_occurred() const { return error_occurred_; } + bool error_occurred() const { return internal::SkippedWithError == skipped_; } // REQUIRES: called exactly once per iteration of the benchmarking loop. // Set the manually measured time for this benchmark iteration, which @@ -878,7 +913,7 @@ class BENCHMARK_EXPORT State { private: bool started_; bool finished_; - bool error_occurred_; + internal::Skipped skipped_; // items we don't need on the first cache line std::vector range_; @@ -933,7 +968,7 @@ inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n, } if (!started_) { StartKeepRunning(); - if (!error_occurred_ && total_iterations_ >= n) { + if (!skipped() && total_iterations_ >= n) { total_iterations_ -= n; return true; } @@ -963,7 +998,7 @@ struct State::StateIterator { BENCHMARK_ALWAYS_INLINE explicit StateIterator(State* st) - : cached_(st->error_occurred_ ? 0 : st->max_iterations), parent_(st) {} + : cached_(st->skipped() ? 0 : st->max_iterations), parent_(st) {} public: BENCHMARK_ALWAYS_INLINE @@ -1662,7 +1697,7 @@ class BENCHMARK_EXPORT BenchmarkReporter { Run() : run_type(RT_Iteration), aggregate_unit(kTime), - error_occurred(false), + skipped(internal::NotSkipped), iterations(1), threads(1), time_unit(GetDefaultTimeUnit()), @@ -1685,8 +1720,8 @@ class BENCHMARK_EXPORT BenchmarkReporter { std::string aggregate_name; StatisticUnit aggregate_unit; std::string report_label; // Empty if not set by benchmark. - bool error_occurred; - std::string error_message; + internal::Skipped skipped; + std::string skip_message; IterationCount iterations; int64_t threads; diff --git a/src/benchmark.cc b/src/benchmark.cc index b8eda00831..f06f36845f 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -166,7 +166,7 @@ State::State(std::string name, IterationCount max_iters, max_iterations(max_iters), started_(false), finished_(false), - error_occurred_(false), + skipped_(internal::NotSkipped), range_(ranges), complexity_n_(0), name_(std::move(name)), @@ -198,9 +198,8 @@ State::State(std::string name, IterationCount max_iters, #endif // Offset tests to ensure commonly accessed data is on the first cache line. const int cache_line_size = 64; - static_assert(offsetof(State, error_occurred_) <= - (cache_line_size - sizeof(error_occurred_)), - ""); + static_assert( + offsetof(State, skipped_) <= (cache_line_size - sizeof(skipped_)), ""); #if defined(__INTEL_COMPILER) #pragma warning pop #elif defined(__GNUC__) @@ -213,7 +212,7 @@ State::State(std::string name, IterationCount max_iters, void State::PauseTiming() { // Add in time accumulated so far - BM_CHECK(started_ && !finished_ && !error_occurred_); + BM_CHECK(started_ && !finished_ && !skipped()); timer_->StopTimer(); if (perf_counters_measurement_) { std::vector> measurements; @@ -230,21 +229,35 @@ void State::PauseTiming() { } void State::ResumeTiming() { - BM_CHECK(started_ && !finished_ && !error_occurred_); + BM_CHECK(started_ && !finished_ && !skipped()); timer_->StartTimer(); if (perf_counters_measurement_) { perf_counters_measurement_->Start(); } } +void State::SkipWithMessage(const char* msg) { + BM_CHECK(msg); + skipped_ = internal::SkippedWithMessage; + { + MutexLock l(manager_->GetBenchmarkMutex()); + if (internal::NotSkipped == manager_->results.skipped_) { + manager_->results.skip_message_ = msg; + manager_->results.skipped_ = skipped_; + } + } + total_iterations_ = 0; + if (timer_->running()) timer_->StopTimer(); +} + void State::SkipWithError(const char* msg) { BM_CHECK(msg); - error_occurred_ = true; + skipped_ = internal::SkippedWithError; { MutexLock l(manager_->GetBenchmarkMutex()); - if (manager_->results.has_error_ == false) { - manager_->results.error_message_ = msg; - manager_->results.has_error_ = true; + if (internal::NotSkipped == manager_->results.skipped_) { + manager_->results.skip_message_ = msg; + manager_->results.skipped_ = skipped_; } } total_iterations_ = 0; @@ -263,14 +276,14 @@ void State::SetLabel(const char* label) { void State::StartKeepRunning() { BM_CHECK(!started_ && !finished_); started_ = true; - total_iterations_ = error_occurred_ ? 0 : max_iterations; + total_iterations_ = skipped() ? 0 : max_iterations; manager_->StartStopBarrier(); - if (!error_occurred_) ResumeTiming(); + if (!skipped()) ResumeTiming(); } void State::FinishKeepRunning() { - BM_CHECK(started_ && (!finished_ || error_occurred_)); - if (!error_occurred_) { + BM_CHECK(started_ && (!finished_ || skipped())); + if (!skipped()) { PauseTiming(); } // Total iterations has now wrapped around past 0. Fix this. diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 58147ca7e6..62383ea8a0 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -80,8 +80,8 @@ BenchmarkReporter::Run CreateRunReport( report.run_name = b.name(); report.family_index = b.family_index(); report.per_family_instance_index = b.per_family_instance_index(); - report.error_occurred = results.has_error_; - report.error_message = results.error_message_; + report.skipped = results.skipped_; + report.skip_message = results.skip_message_; report.report_label = results.report_label_; // This is the total iterations across all threads. report.iterations = results.iterations; @@ -90,7 +90,7 @@ BenchmarkReporter::Run CreateRunReport( report.repetition_index = repetition_index; report.repetitions = repeats; - if (!report.error_occurred) { + if (!report.skipped) { if (b.use_manual_time()) { report.real_accumulated_time = results.manual_time_used; } else { @@ -130,7 +130,7 @@ void RunInThread(const BenchmarkInstance* b, IterationCount iters, State st = b->Run(iters, thread_id, &timer, manager, perf_counters_measurement); - BM_CHECK(st.error_occurred() || st.iterations() >= st.max_iterations) + BM_CHECK(st.skipped() || st.iterations() >= st.max_iterations) << "Benchmark returned before State::KeepRunning() returned false!"; { MutexLock l(manager->GetBenchmarkMutex()); @@ -341,7 +341,7 @@ bool BenchmarkRunner::ShouldReportIterationResults( // Determine if this run should be reported; // Either it has run for a sufficient amount of time // or because an error was reported. - return i.results.has_error_ || + return i.results.skipped_ || i.iters >= kMaxIterations || // Too many iterations already. i.seconds >= GetMinTimeToApply() || // The elapsed time is large enough. @@ -477,7 +477,7 @@ void BenchmarkRunner::DoOneRepetition() { if (reports_for_family) { ++reports_for_family->num_runs_done; - if (!report.error_occurred) reports_for_family->Runs.push_back(report); + if (!report.skipped) reports_for_family->Runs.push_back(report); } run_results.non_aggregates.push_back(report); diff --git a/src/console_reporter.cc b/src/console_reporter.cc index f3d81b253b..10e05e133e 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -135,9 +135,13 @@ void ConsoleReporter::PrintRunData(const Run& result) { printer(Out, name_color, "%-*s ", name_field_width_, result.benchmark_name().c_str()); - if (result.error_occurred) { + if (internal::SkippedWithError == result.skipped) { printer(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'", - result.error_message.c_str()); + result.skip_message.c_str()); + printer(Out, COLOR_DEFAULT, "\n"); + return; + } else if (internal::SkippedWithMessage == result.skipped) { + printer(Out, COLOR_WHITE, "SKIPPED: \'%s\'", result.skip_message.c_str()); printer(Out, COLOR_DEFAULT, "\n"); return; } diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 83c94573f5..7b56da107e 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -109,10 +109,10 @@ BENCHMARK_EXPORT void CSVReporter::PrintRunData(const Run& run) { std::ostream& Out = GetOutputStream(); Out << CsvEscape(run.benchmark_name()) << ","; - if (run.error_occurred) { + if (run.skipped) { Out << std::string(elements.size() - 3, ','); - Out << "true,"; - Out << CsvEscape(run.error_message) << "\n"; + Out << std::boolalpha << (internal::SkippedWithError == run.skipped) << ","; + Out << CsvEscape(run.skip_message) << "\n"; return; } diff --git a/src/json_reporter.cc b/src/json_reporter.cc index d55a0e6f0b..36efbf0b13 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -254,9 +254,12 @@ void JSONReporter::PrintRunData(Run const& run) { BENCHMARK_UNREACHABLE(); }()) << ",\n"; } - if (run.error_occurred) { - out << indent << FormatKV("error_occurred", run.error_occurred) << ",\n"; - out << indent << FormatKV("error_message", run.error_message) << ",\n"; + if (internal::SkippedWithError == run.skipped) { + out << indent << FormatKV("error_occurred", true) << ",\n"; + out << indent << FormatKV("error_message", run.skip_message) << ",\n"; + } else if (internal::SkippedWithMessage == run.skipped) { + out << indent << FormatKV("skipped", true) << ",\n"; + out << indent << FormatKV("skip_message", run.skip_message) << ",\n"; } if (!run.report_big_o && !run.report_rms) { out << indent << FormatKV("iterations", run.iterations) << ",\n"; diff --git a/src/statistics.cc b/src/statistics.cc index 5ba885ab00..c4b54b271f 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -89,9 +89,8 @@ std::vector ComputeStats( typedef BenchmarkReporter::Run Run; std::vector results; - auto error_count = - std::count_if(reports.begin(), reports.end(), - [](Run const& run) { return run.error_occurred; }); + auto error_count = std::count_if(reports.begin(), reports.end(), + [](Run const& run) { return run.skipped; }); if (reports.size() - error_count < 2) { // We don't report aggregated data if there was a single run. @@ -133,7 +132,7 @@ std::vector ComputeStats( for (Run const& run : reports) { BM_CHECK_EQ(reports[0].benchmark_name(), run.benchmark_name()); BM_CHECK_EQ(run_iterations, run.iterations); - if (run.error_occurred) continue; + if (run.skipped) continue; real_accumulated_time_stat.emplace_back(run.real_accumulated_time); cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time); // user counters diff --git a/src/thread_manager.h b/src/thread_manager.h index 4680285089..819b3c44db 100644 --- a/src/thread_manager.h +++ b/src/thread_manager.h @@ -43,8 +43,8 @@ class ThreadManager { double manual_time_used = 0; int64_t complexity_n = 0; std::string report_label_; - std::string error_message_; - bool has_error_ = false; + std::string skip_message_; + internal::Skipped skipped_ = internal::NotSkipped; UserCounters counters; }; GUARDED_BY(GetBenchmarkMutex()) Result results; diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index b8b52457b2..2dd222a26e 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -35,8 +35,9 @@ struct TestCase { void CheckRun(Run const& run) const { BM_CHECK(name == run.benchmark_name()) << "expected " << name << " got " << run.benchmark_name(); - BM_CHECK(error_occurred == run.error_occurred); - BM_CHECK(error_message == run.error_message); + BM_CHECK_EQ(error_occurred, + benchmark::internal::SkippedWithError == run.skipped); + BM_CHECK(error_message == run.skip_message); if (error_occurred) { // BM_CHECK(run.iterations == 0); } else { From 060d762d6129ab19af8558bc76983ea82cb6b050 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 8 Mar 2023 18:57:19 +0000 Subject: [PATCH 083/561] use std::string for skip messages (#1571) --- include/benchmark/benchmark.h | 4 ++-- src/benchmark.cc | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index bb29c73d31..783fcd8e90 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -760,7 +760,7 @@ class BENCHMARK_EXPORT State { // the current scope immediately. If the function is called from within // the 'KeepRunning()' loop the current iteration will finish. It is the users // responsibility to exit the scope as needed. - void SkipWithMessage(const char* msg); + void SkipWithMessage(const std::string& msg); // REQUIRES: 'SkipWithMessage(...)' or 'SkipWithError(...)' has not been // called previously by the current thread. @@ -781,7 +781,7 @@ class BENCHMARK_EXPORT State { // the current scope immediately. If the function is called from within // the 'KeepRunning()' loop the current iteration will finish. It is the users // responsibility to exit the scope as needed. - void SkipWithError(const char* msg); + void SkipWithError(const std::string& msg); // Returns true if 'SkipWithMessage(...)' or 'SkipWithError(...)' was called. bool skipped() const { return internal::NotSkipped != skipped_; } diff --git a/src/benchmark.cc b/src/benchmark.cc index f06f36845f..1937eea37c 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -236,8 +236,7 @@ void State::ResumeTiming() { } } -void State::SkipWithMessage(const char* msg) { - BM_CHECK(msg); +void State::SkipWithMessage(const std::string& msg) { skipped_ = internal::SkippedWithMessage; { MutexLock l(manager_->GetBenchmarkMutex()); @@ -250,8 +249,7 @@ void State::SkipWithMessage(const char* msg) { if (timer_->running()) timer_->StopTimer(); } -void State::SkipWithError(const char* msg) { - BM_CHECK(msg); +void State::SkipWithError(const std::string& msg) { skipped_ = internal::SkippedWithError; { MutexLock l(manager_->GetBenchmarkMutex()); From f32748c372f97bd158baf11ca8e4030965422340 Mon Sep 17 00:00:00 2001 From: Mike Apodaca Date: Fri, 10 Mar 2023 04:38:11 -0800 Subject: [PATCH 084/561] [FR] Provide public accessors to benchmark name and arguments #1551 (#1563) * [FR] Provide public accessors to benchmark name and arguments #1551 * Update AUTHORS and CONTRIBUTORS * Update benchmark_register.cc * Fix lint formatting --- AUTHORS | 1 + CONTRIBUTORS | 1 + include/benchmark/benchmark.h | 3 +++ src/benchmark_register.cc | 8 ++++++++ 4 files changed, 13 insertions(+) diff --git a/AUTHORS b/AUTHORS index b7b3b2e493..bafecaddb5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -46,6 +46,7 @@ Lei Xu Marcel Jacobse Matt Clarkson Maxim Vafin +Mike Apodaca MongoDB Inc. Nick Hutchinson Norman Heino diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 37b000a19f..56f03e2d62 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -67,6 +67,7 @@ Lei Xu Marcel Jacobse Matt Clarkson Maxim Vafin +Mike Apodaca Nick Hutchinson Norman Heino Oleksandr Sochka diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 783fcd8e90..3e7e1dc5a2 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1245,7 +1245,10 @@ class BENCHMARK_EXPORT Benchmark { explicit Benchmark(const char* name); void SetName(const char* name); + public: + const char* GetName() const; int ArgsCnt() const; + const char* GetArgName(int arg) const; private: friend class BenchmarkFamilies; diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index eae2c320f6..4503dd1de9 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -470,6 +470,8 @@ Benchmark* Benchmark::ThreadPerCpu() { void Benchmark::SetName(const char* name) { name_ = name; } +const char* Benchmark::GetName() const { return name_.c_str(); } + int Benchmark::ArgsCnt() const { if (args_.empty()) { if (arg_names_.empty()) return -1; @@ -478,6 +480,12 @@ int Benchmark::ArgsCnt() const { return static_cast(args_.front().size()); } +const char* Benchmark::GetArgName(int arg) const { + BM_CHECK_GE(arg, 0); + BM_CHECK_LT(arg, static_cast(arg_names_.size())); + return arg_names_[arg].c_str(); +} + TimeUnit Benchmark::GetTimeUnit() const { return use_default_time_unit_ ? GetDefaultTimeUnit() : time_unit_; } From 1b507cbf104f7226ade1dd23abe92630e818d54b Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Sat, 11 Mar 2023 14:09:45 +0000 Subject: [PATCH 085/561] simplify setting C++ standard --- CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5442bf768a..f884fae4d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,10 +128,6 @@ if (BENCHMARK_BUILD_32_BITS) add_required_cxx_compiler_flag(-m32) endif() -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - if (MSVC) set(BENCHMARK_CXX_STANDARD 14) else() From 9f7dc386be54976c251775c5d0f38919f0df0083 Mon Sep 17 00:00:00 2001 From: Henrique Bucher <11621271+HFTrader@users.noreply.github.com> Date: Mon, 13 Mar 2023 07:34:12 -0500 Subject: [PATCH 086/561] Address warnings on NVIDIA nvc++ (#1573) * Address warnings on NVIDIA nvc++ Types of warnings were being generated: 1. Deprecated warnings - solved by defining the relevant BENCHMARK_* macros for nvc++ and adding pragma suppress on a couple of .cc files 2. Setup/TearDown const vs non-const partial override - solved by adding non-const version 3. Static but not referenced - added diagnostic suppress for that file * Modified manually to comply with CD/CI * Revert partial override * Suppress warnings from tests if compiler is NVHPC --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- include/benchmark/benchmark.h | 9 ++++++++- src/benchmark.cc | 7 +++++++ src/timers.cc | 3 +++ test/CMakeLists.txt | 3 +++ test/clobber_memory_assembly_test.cc | 1 + test/donotoptimize_assembly_test.cc | 1 + 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 3e7e1dc5a2..153cbba2b8 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -243,13 +243,20 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #define BENCHMARK_INTERNAL_TOSTRING(x) BENCHMARK_INTERNAL_TOSTRING2(x) // clang-format off -#if defined(__GNUC__) && !defined(__NVCC__) || defined(__clang__) +#if (defined(__GNUC__) && !defined(__NVCC__) && !defined(__NVCOMPILER)) || defined(__clang__) #define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) #define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) #define BENCHMARK_DISABLE_DEPRECATED_WARNING \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("GCC diagnostic pop") +#elif defined(__NVCOMPILER) +#define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) +#define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ + _Pragma("diagnostic push") \ + _Pragma("diag_suppress deprecated_entity_with_custom_message") +#define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("diagnostic pop") #else #define BENCHMARK_BUILTIN_EXPECT(x, y) x #define BENCHMARK_DEPRECATED_MSG(msg) diff --git a/src/benchmark.cc b/src/benchmark.cc index 1937eea37c..140884029c 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -195,6 +195,10 @@ State::State(std::string name, IterationCount max_iters, #if defined(__NVCC__) #pragma nv_diagnostic push #pragma nv_diag_suppress 1427 +#endif +#if defined(__NVCOMPILER) +#pragma diagnostic push +#pragma diag_suppress offset_in_non_POD_nonstandard #endif // Offset tests to ensure commonly accessed data is on the first cache line. const int cache_line_size = 64; @@ -208,6 +212,9 @@ State::State(std::string name, IterationCount max_iters, #if defined(__NVCC__) #pragma nv_diagnostic pop #endif +#if defined(__NVCOMPILER) +#pragma diagnostic pop +#endif } void State::PauseTiming() { diff --git a/src/timers.cc b/src/timers.cc index 89ddbfb030..b23feea8ba 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -67,6 +67,9 @@ namespace benchmark { #if defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" #endif +#if defined(__NVCOMPILER) +#pragma diag_suppress declared_but_not_referenced +#endif namespace { #if defined(BENCHMARK_OS_WINDOWS) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cfef13bd77..212cfd2373 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,6 +46,9 @@ target_link_libraries(output_test_helper PRIVATE benchmark::benchmark) macro(compile_benchmark_test name) add_executable(${name} "${name}.cc") target_link_libraries(${name} benchmark::benchmark_main ${CMAKE_THREAD_LIBS_INIT}) + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "NVHPC") + target_compile_options( ${name} PRIVATE --diag_suppress partial_override ) + endif() endmacro(compile_benchmark_test) macro(compile_benchmark_test_with_main name) diff --git a/test/clobber_memory_assembly_test.cc b/test/clobber_memory_assembly_test.cc index ab269130cd..54e26ccdad 100644 --- a/test/clobber_memory_assembly_test.cc +++ b/test/clobber_memory_assembly_test.cc @@ -3,6 +3,7 @@ #ifdef __clang__ #pragma clang diagnostic ignored "-Wreturn-type" #endif +BENCHMARK_DISABLE_DEPRECATED_WARNING extern "C" { diff --git a/test/donotoptimize_assembly_test.cc b/test/donotoptimize_assembly_test.cc index 70e780a5f0..dc286f53e2 100644 --- a/test/donotoptimize_assembly_test.cc +++ b/test/donotoptimize_assembly_test.cc @@ -3,6 +3,7 @@ #ifdef __clang__ #pragma clang diagnostic ignored "-Wreturn-type" #endif +BENCHMARK_DISABLE_DEPRECATED_WARNING extern "C" { From 68aa1903b18f6967a608f3584db3eac28a4f883c Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:18:00 +0000 Subject: [PATCH 087/561] add '@' to correctly reference build file for libpfm (#1575) --- bazel/benchmark_deps.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index bc1fc9f1ea..0e279fbcf7 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -58,9 +58,9 @@ def benchmark_deps(): # Downloaded from v4.9.0 tag at https://sourceforge.net/p/perfmon2/libpfm4/ref/master/tags/ http_archive( name = "libpfm", - build_file = "//tools:libpfm.BUILD.bazel", + build_file = "@//tools:libpfm.BUILD.bazel", sha256 = "5da5f8872bde14b3634c9688d980f68bda28b510268723cc12973eedbab9fecc", type = "tar.gz", strip_prefix = "libpfm-4.11.0", urls = ["https://sourceforge.net/projects/perfmon2/files/libpfm4/libpfm-4.11.0.tar.gz/download"], - ) \ No newline at end of file + ) From 46d3c84518ee71e36fa42c50b1fe3758a45d1d3b Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 14 Mar 2023 13:10:27 +0000 Subject: [PATCH 088/561] Convert uses of `const char*` to `std::string` (#1567) * Convert uses of const char* to std::string * fix sanitizer builds * reformat user guide * include python bindings * clang-format --- bindings/python/google_benchmark/benchmark.cc | 6 ++--- docs/user_guide.md | 17 +++++++----- include/benchmark/benchmark.h | 26 ++++++++----------- src/benchmark.cc | 2 +- src/benchmark_register.cc | 6 ++--- src/benchmark_runner.cc | 6 ++--- src/json_reporter.cc | 3 ++- test/output_test.h | 10 +++---- test/output_test_helper.cc | 21 ++++++++------- test/register_benchmark_test.cc | 12 ++++----- test/skip_with_error_test.cc | 3 ++- 11 files changed, 56 insertions(+), 56 deletions(-) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index cf2da2e812..f44476901c 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -34,7 +34,7 @@ std::vector Initialize(const std::vector& argv) { return remaining_argv; } -benchmark::internal::Benchmark* RegisterBenchmark(const char* name, +benchmark::internal::Benchmark* RegisterBenchmark(const std::string& name, nb::callable f) { return benchmark::RegisterBenchmark( name, [f](benchmark::State& state) { f(&state); }); @@ -165,8 +165,8 @@ NB_MODULE(_benchmark, m) { .def_prop_rw("complexity_n", &State::complexity_length_n, &State::SetComplexityN) .def_prop_rw("items_processed", &State::items_processed, - &State::SetItemsProcessed) - .def("set_label", (void (State::*)(const char*)) & State::SetLabel) + &State::SetItemsProcessed) + .def("set_label", &State::SetLabel) .def("range", &State::range, nb::arg("pos") = 0) .def_prop_ro("iterations", &State::iterations) .def_prop_ro("name", &State::name) diff --git a/docs/user_guide.md b/docs/user_guide.md index 7fffb60364..133fca5b6f 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -56,7 +56,7 @@ [Exiting with an Error](#exiting-with-an-error) -[A Faster KeepRunning Loop](#a-faster-keep-running-loop) +[A Faster `KeepRunning` Loop](#a-faster-keep-running-loop) ## Benchmarking Tips @@ -271,10 +271,12 @@ information about the machine on which the benchmarks are run. Global setup/teardown specific to each benchmark can be done by passing a callback to Setup/Teardown: -The setup/teardown callbacks will be invoked once for each benchmark. -If the benchmark is multi-threaded (will run in k threads), they will be invoked exactly once before -each run with k threads. -If the benchmark uses different size groups of threads, the above will be true for each size group. +The setup/teardown callbacks will be invoked once for each benchmark. If the +benchmark is multi-threaded (will run in k threads), they will be invoked +exactly once before each run with k threads. + +If the benchmark uses different size groups of threads, the above will be true +for each size group. Eg., @@ -1142,7 +1144,7 @@ int main(int argc, char** argv) { When errors caused by external influences, such as file I/O and network communication, occur within a benchmark the -`State::SkipWithError(const char* msg)` function can be used to skip that run +`State::SkipWithError(const std::string& msg)` function can be used to skip that run of benchmark and report the error. Note that only future iterations of the `KeepRunning()` are skipped. For the ranged-for version of the benchmark loop Users must explicitly exit the loop, otherwise all iterations will be performed. @@ -1253,7 +1255,8 @@ the benchmark loop should be preferred. If you see this error: ``` -***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead. +***WARNING*** CPU scaling is enabled, the benchmark real time measurements may +be noisy and will incur extra overhead. ``` you might want to disable the CPU frequency scaling while running the diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 153cbba2b8..e44d534128 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -865,11 +865,7 @@ class BENCHMARK_EXPORT State { // BM_Compress 50 50 14115038 compress:27.3% // // REQUIRES: a benchmark has exited its benchmarking loop. - void SetLabel(const char* label); - - void BENCHMARK_ALWAYS_INLINE SetLabel(const std::string& str) { - this->SetLabel(str.c_str()); - } + void SetLabel(const std::string& label); // Range arguments for this run. CHECKs if the argument has been set. BENCHMARK_ALWAYS_INLINE @@ -1249,8 +1245,8 @@ class BENCHMARK_EXPORT Benchmark { TimeUnit GetTimeUnit() const; protected: - explicit Benchmark(const char* name); - void SetName(const char* name); + explicit Benchmark(const std::string& name); + void SetName(const std::string& name); public: const char* GetName() const; @@ -1305,12 +1301,12 @@ class BENCHMARK_EXPORT Benchmark { // the specified functor 'fn'. // // RETURNS: A pointer to the registered benchmark. -internal::Benchmark* RegisterBenchmark(const char* name, +internal::Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn); #if defined(BENCHMARK_HAS_CXX11) template -internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn); +internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn); #endif // Remove all registered benchmarks. All pointers to previously registered @@ -1322,7 +1318,7 @@ namespace internal { // (ie those created using the BENCHMARK(...) macros. class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark { public: - FunctionBenchmark(const char* name, Function* func) + FunctionBenchmark(const std::string& name, Function* func) : Benchmark(name), func_(func) {} void Run(State& st) BENCHMARK_OVERRIDE; @@ -1339,20 +1335,20 @@ class LambdaBenchmark : public Benchmark { private: template - LambdaBenchmark(const char* name, OLambda&& lam) + LambdaBenchmark(const std::string& name, OLambda&& lam) : Benchmark(name), lambda_(std::forward(lam)) {} LambdaBenchmark(LambdaBenchmark const&) = delete; template // NOLINTNEXTLINE(readability-redundant-declaration) - friend Benchmark* ::benchmark::RegisterBenchmark(const char*, Lam&&); + friend Benchmark* ::benchmark::RegisterBenchmark(const std::string&, Lam&&); Lambda lambda_; }; #endif } // namespace internal -inline internal::Benchmark* RegisterBenchmark(const char* name, +inline internal::Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn) { return internal::RegisterBenchmarkInternal( ::new internal::FunctionBenchmark(name, fn)); @@ -1360,7 +1356,7 @@ inline internal::Benchmark* RegisterBenchmark(const char* name, #ifdef BENCHMARK_HAS_CXX11 template -internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn) { +internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { using BenchType = internal::LambdaBenchmark::type>; return internal::RegisterBenchmarkInternal( @@ -1371,7 +1367,7 @@ internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn) { #if defined(BENCHMARK_HAS_CXX11) && \ (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) template -internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn, +internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn, Args&&... args) { return benchmark::RegisterBenchmark( name, [=](benchmark::State& st) { fn(st, args...); }); diff --git a/src/benchmark.cc b/src/benchmark.cc index 140884029c..f1633b703f 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -273,7 +273,7 @@ void State::SetIterationTime(double seconds) { timer_->SetIterationTime(seconds); } -void State::SetLabel(const char* label) { +void State::SetLabel(const std::string& label) { MutexLock l(manager_->GetBenchmarkMutex()); manager_->results.report_label_ = label; } diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 4503dd1de9..e447c9a2d3 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -204,7 +204,7 @@ bool FindBenchmarksInternal(const std::string& re, // Benchmark //=============================================================================// -Benchmark::Benchmark(const char* name) +Benchmark::Benchmark(const std::string& name) : name_(name), aggregation_report_mode_(ARM_Unspecified), time_unit_(GetDefaultTimeUnit()), @@ -230,7 +230,7 @@ Benchmark::Benchmark(const char* name) Benchmark::~Benchmark() {} Benchmark* Benchmark::Name(const std::string& name) { - SetName(name.c_str()); + SetName(name); return this; } @@ -468,7 +468,7 @@ Benchmark* Benchmark::ThreadPerCpu() { return this; } -void Benchmark::SetName(const char* name) { name_ = name; } +void Benchmark::SetName(const std::string& name) { name_ = name; } const char* Benchmark::GetName() const { return name_.c_str(); } diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 62383ea8a0..f7ae424397 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -177,11 +177,10 @@ BenchTimeType ParseBenchMinTime(const std::string& value) { } if (value.back() == 'x') { - const char* iters_str = value.c_str(); char* p_end; // Reset errno before it's changed by strtol. errno = 0; - IterationCount num_iters = std::strtol(iters_str, &p_end, 10); + IterationCount num_iters = std::strtol(value.c_str(), &p_end, 10); // After a valid parse, p_end should have been set to // point to the 'x' suffix. @@ -194,7 +193,6 @@ BenchTimeType ParseBenchMinTime(const std::string& value) { return ret; } - const char* time_str = value.c_str(); bool has_suffix = value.back() == 's'; if (!has_suffix) { BM_VLOG(0) << "Value passed to --benchmark_min_time should have a suffix. " @@ -204,7 +202,7 @@ BenchTimeType ParseBenchMinTime(const std::string& value) { char* p_end; // Reset errno before it's changed by strtod. errno = 0; - double min_time = std::strtod(time_str, &p_end); + double min_time = std::strtod(value.c_str(), &p_end); // After a successful parse, p_end should point to the suffix 's', // or the end of the string if the suffix was omitted. diff --git a/src/json_reporter.cc b/src/json_reporter.cc index 36efbf0b13..6559dfd5e6 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -297,7 +297,8 @@ void JSONReporter::PrintRunData(Run const& run) { out << ",\n" << indent << FormatKV("max_bytes_used", memory_result.max_bytes_used); - auto report_if_present = [&out, &indent](const char* label, int64_t val) { + auto report_if_present = [&out, &indent](const std::string& label, + int64_t val) { if (val != MemoryManager::TombstoneValue) out << ",\n" << indent << FormatKV(label, val); }; diff --git a/test/output_test.h b/test/output_test.h index c6ff8ef2d3..c08fe1d87e 100644 --- a/test/output_test.h +++ b/test/output_test.h @@ -85,7 +85,7 @@ std::string GetFileReporterOutput(int argc, char* argv[]); struct Results; typedef std::function ResultsCheckFn; -size_t AddChecker(const char* bm_name_pattern, const ResultsCheckFn& fn); +size_t AddChecker(const std::string& bm_name_pattern, const ResultsCheckFn& fn); // Class holding the results of a benchmark. // It is passed in calls to checker functions. @@ -117,7 +117,7 @@ struct Results { // get the string for a result by name, or nullptr if the name // is not found - const std::string* Get(const char* entry_name) const { + const std::string* Get(const std::string& entry_name) const { auto it = values.find(entry_name); if (it == values.end()) return nullptr; return &it->second; @@ -126,12 +126,12 @@ struct Results { // get a result by name, parsed as a specific type. // NOTE: for counters, use GetCounterAs instead. template - T GetAs(const char* entry_name) const; + T GetAs(const std::string& entry_name) const; // counters are written as doubles, so they have to be read first // as a double, and only then converted to the asked type. template - T GetCounterAs(const char* entry_name) const { + T GetCounterAs(const std::string& entry_name) const { double dval = GetAs(entry_name); T tval = static_cast(dval); return tval; @@ -139,7 +139,7 @@ struct Results { }; template -T Results::GetAs(const char* entry_name) const { +T Results::GetAs(const std::string& entry_name) const { auto* sv = Get(entry_name); BM_CHECK(sv != nullptr && !sv->empty()); std::stringstream ss; diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index 986c4adbed..241af5c916 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -299,7 +299,7 @@ std::vector ResultsChecker::SplitCsv_(const std::string& line) { } // end namespace internal -size_t AddChecker(const char* bm_name, const ResultsCheckFn& fn) { +size_t AddChecker(const std::string& bm_name, const ResultsCheckFn& fn) { auto& rc = internal::GetResultsChecker(); rc.Add(bm_name, fn); return rc.results.size(); @@ -394,14 +394,14 @@ void RunOutputTests(int argc, char* argv[]) { benchmark::JSONReporter JR; benchmark::CSVReporter CSVR; struct ReporterTest { - const char* name; + std::string name; std::vector& output_cases; std::vector& error_cases; benchmark::BenchmarkReporter& reporter; std::stringstream out_stream; std::stringstream err_stream; - ReporterTest(const char* n, std::vector& out_tc, + ReporterTest(const std::string& n, std::vector& out_tc, std::vector& err_tc, benchmark::BenchmarkReporter& br) : name(n), output_cases(out_tc), error_cases(err_tc), reporter(br) { @@ -409,12 +409,12 @@ void RunOutputTests(int argc, char* argv[]) { reporter.SetErrorStream(&err_stream); } } TestCases[] = { - {"ConsoleReporter", GetTestCaseList(TC_ConsoleOut), + {std::string("ConsoleReporter"), GetTestCaseList(TC_ConsoleOut), GetTestCaseList(TC_ConsoleErr), CR}, - {"JSONReporter", GetTestCaseList(TC_JSONOut), GetTestCaseList(TC_JSONErr), - JR}, - {"CSVReporter", GetTestCaseList(TC_CSVOut), GetTestCaseList(TC_CSVErr), - CSVR}, + {std::string("JSONReporter"), GetTestCaseList(TC_JSONOut), + GetTestCaseList(TC_JSONErr), JR}, + {std::string("CSVReporter"), GetTestCaseList(TC_CSVOut), + GetTestCaseList(TC_CSVErr), CSVR}, }; // Create the test reporter and run the benchmarks. @@ -423,7 +423,8 @@ void RunOutputTests(int argc, char* argv[]) { benchmark::RunSpecifiedBenchmarks(&test_rep); for (auto& rep_test : TestCases) { - std::string msg = std::string("\nTesting ") + rep_test.name + " Output\n"; + std::string msg = + std::string("\nTesting ") + rep_test.name + std::string(" Output\n"); std::string banner(msg.size() - 1, '-'); std::cout << banner << msg << banner << "\n"; @@ -440,7 +441,7 @@ void RunOutputTests(int argc, char* argv[]) { // the checks to subscribees. auto& csv = TestCases[2]; // would use == but gcc spits a warning - BM_CHECK(std::strcmp(csv.name, "CSVReporter") == 0); + BM_CHECK(csv.name == std::string("CSVReporter")); internal::GetResultsChecker().CheckResults(csv.out_stream); } diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index 240c8c2447..d69d144a4e 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -19,11 +19,11 @@ class TestReporter : public benchmark::ConsoleReporter { }; struct TestCase { - std::string name; - const char* label; + const std::string name; + const std::string label; // Note: not explicit as we rely on it being converted through ADD_CASES. - TestCase(const char* xname) : TestCase(xname, nullptr) {} - TestCase(const char* xname, const char* xlabel) + TestCase(const std::string& xname) : TestCase(xname, "") {} + TestCase(const std::string& xname, const std::string& xlabel) : name(xname), label(xlabel) {} typedef benchmark::BenchmarkReporter::Run Run; @@ -32,7 +32,7 @@ struct TestCase { // clang-format off BM_CHECK(name == run.benchmark_name()) << "expected " << name << " got " << run.benchmark_name(); - if (label) { + if (!label.empty()) { BM_CHECK(run.report_label == label) << "expected " << label << " got " << run.report_label; } else { @@ -123,7 +123,7 @@ void TestRegistrationAtRuntime() { { CustomFixture fx; benchmark::RegisterBenchmark("custom_fixture", fx); - AddCases({"custom_fixture"}); + AddCases({std::string("custom_fixture")}); } #endif #ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 2dd222a26e..b4c5e154c4 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -48,7 +48,8 @@ struct TestCase { std::vector ExpectedResults; -int AddCases(const char* base_name, std::initializer_list const& v) { +int AddCases(const std::string& base_name, + std::initializer_list const& v) { for (auto TC : v) { TC.name = base_name + TC.name; ExpectedResults.push_back(std::move(TC)); From efc89f0b524780b1994d5dddd83a92718e5be492 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 14 Mar 2023 13:35:32 +0000 Subject: [PATCH 089/561] link to benchmark directly for tests that aren't link_main_test (#1576) --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 212cfd2373..78d6d51750 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,7 +45,7 @@ target_link_libraries(output_test_helper PRIVATE benchmark::benchmark) macro(compile_benchmark_test name) add_executable(${name} "${name}.cc") - target_link_libraries(${name} benchmark::benchmark_main ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(${name} benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "NVHPC") target_compile_options( ${name} PRIVATE --diag_suppress partial_override ) endif() From 0c34d812e407d677a7c9836a3bec3dd84aa4e71a Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 16 Mar 2023 09:49:12 +0000 Subject: [PATCH 090/561] use 'new_git_repository' in external deps call to work with older bazel versions --- bazel/benchmark_deps.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 0e279fbcf7..be01c7f578 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -1,5 +1,5 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") def benchmark_deps(): """Loads dependencies required to build Google Benchmark.""" @@ -38,14 +38,14 @@ def benchmark_deps(): ) if "com_google_googletest" not in native.existing_rules(): - git_repository( + new_git_repository( name = "com_google_googletest", remote = "https://github.com/google/googletest.git", tag = "release-1.11.0", ) if "nanobind" not in native.existing_rules(): - git_repository( + new_git_repository( name = "nanobind", remote = "https://github.com/wjakob/nanobind.git", commit = "1ffbfe836c9dac599496a170274ee0075094a607", # v0.2.0 From 4b086c26febc39f4636d82a436fd445b9af9501b Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 16 Mar 2023 10:16:23 +0000 Subject: [PATCH 091/561] make libpfm dep work for integrators --- bazel/benchmark_deps.bzl | 2 +- tools/libpfm.BUILD.bazel | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index be01c7f578..df0c085f87 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -58,7 +58,7 @@ def benchmark_deps(): # Downloaded from v4.9.0 tag at https://sourceforge.net/p/perfmon2/libpfm4/ref/master/tags/ http_archive( name = "libpfm", - build_file = "@//tools:libpfm.BUILD.bazel", + build_file = str(Label("@//tools:libpfm.BUILD.bazel")), sha256 = "5da5f8872bde14b3634c9688d980f68bda28b510268723cc12973eedbab9fecc", type = "tar.gz", strip_prefix = "libpfm-4.11.0", diff --git a/tools/libpfm.BUILD.bazel b/tools/libpfm.BUILD.bazel index f661064fd5..62695342aa 100644 --- a/tools/libpfm.BUILD.bazel +++ b/tools/libpfm.BUILD.bazel @@ -14,6 +14,7 @@ make( lib_name = "libpfm", copts = [ "-Wno-format-truncation", + "-Wno-use-after-free", ], visibility = [ "//visibility:public", From d29044d5da4b32e449073a365ad6524fb9bdf884 Mon Sep 17 00:00:00 2001 From: pkasting Date: Thu, 16 Mar 2023 04:07:13 -0700 Subject: [PATCH 092/561] Fix compile warnings about ignoring a [[nodiscard]] type. (#1577) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- test/string_util_gtest.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/test/string_util_gtest.cc b/test/string_util_gtest.cc index 698f2d43eb..8bfdb7a72c 100644 --- a/test/string_util_gtest.cc +++ b/test/string_util_gtest.cc @@ -2,6 +2,8 @@ // statistics_test - Unit tests for src/statistics.cc //===---------------------------------------------------------------------===// +#include + #include "../src/internal_macros.h" #include "../src/string_util.h" #include "gtest/gtest.h" @@ -63,7 +65,10 @@ TEST(StringUtilTest, stoul) { EXPECT_EQ(4ul, pos); } #ifndef BENCHMARK_HAS_NO_EXCEPTIONS - { ASSERT_THROW(benchmark::stoul("this is a test"), std::invalid_argument); } + { + ASSERT_THROW(std::ignore = benchmark::stoul("this is a test"), + std::invalid_argument); + } #endif } @@ -107,7 +112,10 @@ EXPECT_EQ(1ul, pos); EXPECT_EQ(4ul, pos); } #ifndef BENCHMARK_HAS_NO_EXCEPTIONS -{ ASSERT_THROW(benchmark::stoi("this is a test"), std::invalid_argument); } +{ + ASSERT_THROW(std::ignore = benchmark::stoi("this is a test"), + std::invalid_argument); +} #endif } @@ -137,7 +145,10 @@ EXPECT_EQ(1ul, pos); EXPECT_EQ(8ul, pos); } #ifndef BENCHMARK_HAS_NO_EXCEPTIONS -{ ASSERT_THROW(benchmark::stod("this is a test"), std::invalid_argument); } +{ + ASSERT_THROW(std::ignore = benchmark::stod("this is a test"), + std::invalid_argument); +} #endif } From f7547e29ccaed7b64ef4f7495ecfff1c9f6f3d03 Mon Sep 17 00:00:00 2001 From: Shiqing Yan <108403238+shiqing117@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:50:17 +0000 Subject: [PATCH 093/561] Correct libpfm dep for integrators. (#1579) --- bazel/benchmark_deps.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index df0c085f87..e9ca2cec5d 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -58,7 +58,7 @@ def benchmark_deps(): # Downloaded from v4.9.0 tag at https://sourceforge.net/p/perfmon2/libpfm4/ref/master/tags/ http_archive( name = "libpfm", - build_file = str(Label("@//tools:libpfm.BUILD.bazel")), + build_file = str(Label("//tools:libpfm.BUILD.bazel")), sha256 = "5da5f8872bde14b3634c9688d980f68bda28b510268723cc12973eedbab9fecc", type = "tar.gz", strip_prefix = "libpfm-4.11.0", From b177433f3ee2513b1075140c723d73ab8901790f Mon Sep 17 00:00:00 2001 From: Andrii Dushko Date: Thu, 30 Mar 2023 21:17:14 +0000 Subject: [PATCH 094/561] Guard NOMINMAX to prevent redefinition error (#1581) (#1582) Fixes #1581. --- src/internal_macros.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/internal_macros.h b/src/internal_macros.h index 658f157339..8dd7d0c650 100644 --- a/src/internal_macros.h +++ b/src/internal_macros.h @@ -44,7 +44,9 @@ #define BENCHMARK_OS_WINDOWS 1 // WINAPI_FAMILY_PARTITION is defined in winapifamily.h. // We include windows.h which implicitly includes winapifamily.h for compatibility. - #define NOMINMAX + #ifndef NOMINMAX + #define NOMINMAX + #endif #include #if defined(WINAPI_FAMILY_PARTITION) #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) From fba5dd147d34b793e9ae2554f34f36a0bf507c6e Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 3 May 2023 16:55:45 +0100 Subject: [PATCH 095/561] reenable msan sanitizer workflow (#1589) --- .github/libcxx-setup.sh | 43 ++++++++++++++++----------------- .github/workflows/sanitizer.yml | 26 ++++++-------------- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/.github/libcxx-setup.sh b/.github/libcxx-setup.sh index e39e310e41..8773b9c407 100755 --- a/.github/libcxx-setup.sh +++ b/.github/libcxx-setup.sh @@ -1,27 +1,26 @@ #!/usr/bin/env bash +set -e + # Checkout LLVM sources -#git clone --depth=1 https://github.com/llvm/llvm-project.git llvm-project -# +git clone --depth=1 https://github.com/llvm/llvm-project.git llvm-project + ## Setup libc++ options -#if [ -z "$BUILD_32_BITS" ]; then -# export BUILD_32_BITS=OFF && echo disabling 32 bit build -#fi -# -## Build and install libc++ (Use unstable ABI for better sanitizer coverage) -#cd ./llvm-project -#cmake -DCMAKE_C_COMPILER=${CC} \ -# -DCMAKE_CXX_COMPILER=${CXX} \ -# -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -# -DCMAKE_INSTALL_PREFIX=/usr \ -# -DLIBCXX_ABI_UNSTABLE=OFF \ -# -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ -# -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ -# -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \ -# -S llvm -B llvm-build -G "Unix Makefiles" -#make -C llvm-build -j3 cxx cxxabi -#sudo make -C llvm-build install-cxx install-cxxabi -#cd .. +if [ -z "$BUILD_32_BITS" ]; then + export BUILD_32_BITS=OFF && echo disabling 32 bit build +fi -sudo apt update -sudo apt -y install libc++-dev libc++abi-dev +## Build and install libc++ (Use unstable ABI for better sanitizer coverage) +mkdir llvm-build && cd llvm-build +cmake -DCMAKE_C_COMPILER=${CC} \ + -DCMAKE_CXX_COMPILER=${CXX} \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DLIBCXX_ABI_UNSTABLE=OFF \ + -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ + -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ + -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi;libunwind' \ + -G "Unix Makefiles" \ + ../llvm-project/runtimes/ +make -j cxx cxxabi unwind +cd .. diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 4cb93f4a47..86cccf4102 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -9,15 +9,14 @@ env: jobs: job: - name: ${{ matrix.sanitizer }}.${{ matrix.build_type }}.${{ matrix.compiler }} + name: ${{ matrix.sanitizer }}.${{ matrix.build_type }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: build_type: ['Debug', 'RelWithDebInfo'] - sanitizer: ['asan', 'ubsan', 'tsan'] - compiler: ['clang', 'gcc'] - # TODO: add 'msan' above. currently failing and needs investigation. + sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] + steps: - uses: actions/checkout@v3 @@ -46,36 +45,27 @@ jobs: echo "LIBCXX_SANITIZER=Thread" >> $GITHUB_ENV - name: fine-tune asan options - # in clang+asan we get an error from std::regex. ignore it. - if: matrix.sanitizer == 'asan' && matrix.compiler == 'clang' + # in asan we get an error from std::regex. ignore it. + if: matrix.sanitizer == 'asan' run: | echo "ASAN_OPTIONS=alloc_dealloc_mismatch=0" >> $GITHUB_ENV - name: setup clang - if: matrix.compiler == 'clang' uses: egor-tensin/setup-clang@v1 with: version: latest platform: x64 - name: configure clang - if: matrix.compiler == 'clang' run: | echo "CC=cc" >> $GITHUB_ENV echo "CXX=c++" >> $GITHUB_ENV - - name: configure gcc - if: matrix.compiler == 'gcc' - run: | - sudo apt update && sudo apt -y install gcc-10 g++-10 - echo "CC=gcc-10" >> $GITHUB_ENV - echo "CXX=g++-10" >> $GITHUB_ENV - - - name: install llvm stuff - if: matrix.compiler == 'clang' + - name: build libc++ (non-asan) + if: matrix.sanitizer != 'asan' run: | "${GITHUB_WORKSPACE}/.github/libcxx-setup.sh" - echo "EXTRA_CXX_FLAGS=\"-stdlib=libc++\"" >> $GITHUB_ENV + echo "EXTRA_CXX_FLAGS=-stdlib=libc++ -L ${GITHUB_WORKSPACE}/llvm-build/lib -lc++abi -Isystem${GITHUB_WORKSPACE}/llvm-build/include -Isystem${GITHUB_WORKSPACE}/llvm-build/include/c++/v1 -Wl,-rpath,${GITHUB_WORKSPACE}/llvm-build/lib" >> $GITHUB_ENV - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build From 2dd015dfef425c866d9a43f2c67d8b52d709acb6 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Fri, 5 May 2023 11:25:54 +0100 Subject: [PATCH 096/561] update version to v1.8.0 --- CMakeLists.txt | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f884fae4d7..b01cf748ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.10...3.22) -project (benchmark VERSION 1.7.1 LANGUAGES CXX) +project (benchmark VERSION 1.8.0 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index e6ef8e7d3c..a118dad7e1 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -69,7 +69,7 @@ def my_benchmark(state): "State", ] -__version__ = "1.7.1" +__version__ = "1.8.0" class __OptionMaker: From 318dd44225e4a6f0af191bbe0e265cf28533626d Mon Sep 17 00:00:00 2001 From: Andy Christiansen Date: Wed, 10 May 2023 11:18:43 +0200 Subject: [PATCH 097/561] Disable debug-only test in release builds to avoid expected failures. (#1595) Co-authored-by: Andy Christiansen --- test/diagnostics_test.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index fda14b3d57..0cd3edbd42 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -76,7 +76,16 @@ void BM_diagnostic_test_keep_running(benchmark::State& state) { BENCHMARK(BM_diagnostic_test_keep_running); int main(int argc, char* argv[]) { +#ifdef NDEBUG + // This test is exercising functionality for debug builds, which are not + // available in release builds. Skip the test if we are in that environment + // to avoid a test failure. + std::cout << "Diagnostic test disabled in release build" << std::endl; + (void)argc; + (void)argv; +#else benchmark::internal::GetAbortHandler() = &TestHandler; benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); +#endif } From fec77322b41b099cc65e0f616680554a54d2bda5 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Thu, 11 May 2023 03:40:05 -0400 Subject: [PATCH 098/561] Fix code triggering -Wsign-conversion (#1596) * Fix code triggering -Wsign-conversion * more test --- test/benchmark_min_time_flag_iters_test.cc | 2 +- test/benchmark_min_time_flag_time_test.cc | 2 +- test/perf_counters_gtest.cc | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index eb9414acdb..3de93a7505 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -46,7 +46,7 @@ BENCHMARK(BM_MyBench); int main(int argc, char** argv) { // Make a fake argv and append the new --benchmark_min_time= to it. int fake_argc = argc + 1; - const char** fake_argv = new const char*[fake_argc]; + const char** fake_argv = new const char*[static_cast(fake_argc)]; for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; fake_argv[argc] = "--benchmark_min_time=4x"; diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index b172cccba7..04a82eb95b 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -71,7 +71,7 @@ BENCHMARK(BM_MyBench); int main(int argc, char** argv) { // Make a fake argv and append the new --benchmark_min_time= to it. int fake_argc = argc + 1; - const char** fake_argv = new const char*[fake_argc]; + const char** fake_argv = new const char*[static_cast(fake_argc)]; for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index e73ebc5886..bb55aff7c5 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -169,8 +169,8 @@ TEST(PerfCountersTest, CreateExistingMeasurements) { std::vector> measurements; // Start all counters together to see if they hold - int max_counters = kMaxCounters; - for (int i = 0; i < kMaxCounters; ++i) { + size_t max_counters = kMaxCounters; + for (size_t i = 0; i < kMaxCounters; ++i) { auto& counter(*perf_counter_measurements[i]); EXPECT_EQ(counter.num_counters(), 1); if (!counter.Start()) { @@ -182,13 +182,13 @@ TEST(PerfCountersTest, CreateExistingMeasurements) { ASSERT_GE(max_counters, kMinValidCounters); // Start all together - for (int i = 0; i < max_counters; ++i) { + for (size_t i = 0; i < max_counters; ++i) { auto& counter(*perf_counter_measurements[i]); EXPECT_TRUE(counter.Stop(measurements) || (i >= kMinValidCounters)); } // Start/stop individually - for (int i = 0; i < max_counters; ++i) { + for (size_t i = 0; i < max_counters; ++i) { auto& counter(*perf_counter_measurements[i]); measurements.clear(); counter.Start(); From bb9aafaa6c622057449eda4580e1a9c097b18f68 Mon Sep 17 00:00:00 2001 From: Andy Christiansen Date: Thu, 11 May 2023 10:18:18 +0200 Subject: [PATCH 099/561] Update Python version to PY3, as indicated by the actual source file. (#1598) Co-authored-by: Andy Christiansen --- tools/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 5895883a2e..c0cbc64e27 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -12,7 +12,7 @@ py_library( py_binary( name = "compare", srcs = ["compare.py"], - python_version = "PY2", + python_version = "PY3", deps = [ ":gbench", ], From 4b13b3d47a9ad3bb4b83bde3c3841b2b0b5c5789 Mon Sep 17 00:00:00 2001 From: Pavel Novikov Date: Mon, 15 May 2023 12:07:00 +0300 Subject: [PATCH 100/561] Fixed a typo in docs (#1600) --- docs/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 133fca5b6f..2ceb13eb59 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -861,7 +861,7 @@ BENCHMARK(BM_OpenMP)->Range(8, 8<<10); // Measure the user-visible time, the wall clock (literally, the time that // has passed on the clock on the wall), use it to decide for how long to -// run the benchmark loop. This will always be meaningful, an will match the +// run the benchmark loop. This will always be meaningful, and will match the // time spent by the main thread in single-threaded case, in general decreasing // with the number of internal threads doing the work. BENCHMARK(BM_OpenMP)->Range(8, 8<<10)->UseRealTime(); From 604f6fd3f4b34a84ec4eb4db81d842fa4db829cd Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 30 May 2023 08:44:26 +0100 Subject: [PATCH 101/561] Add project name to version message Inspired by paulcaprioli --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b01cf748ca..34a74e438d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ else() set(VERSION "${GIT_VERSION}") endif() # Tell the user what versions we are using -message(STATUS "Version: ${VERSION}") +message(STATUS "Google Benchmark version: ${VERSION}") # The version of the libraries set(GENERIC_LIB_VERSION ${VERSION}) From df9a99d998d9f038a53a970a77ce31c8c2a882ce Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Mon, 19 Jun 2023 10:35:52 +0300 Subject: [PATCH 102/561] Fix pass rvalue to DoNotOptimize (#1608) * Fix pass rvalue to DoNotOptimize #1584 * Add test --- include/benchmark/benchmark.h | 20 ++++++++++++++++---- test/donotoptimize_test.cc | 5 +++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index e44d534128..558aca8ddc 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -465,7 +465,13 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { } template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize( +#ifdef BENCHMARK_HAS_CXX11 + Tp&& value +#else + Tp& value +#endif +) { #if defined(__clang__) asm volatile("" : "+r,m"(value) : : "memory"); #else @@ -501,7 +507,7 @@ template inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value && (sizeof(Tp) <= sizeof(Tp*))>::type - DoNotOptimize(Tp& value) { + DoNotOptimize(Tp&& value) { asm volatile("" : "+m,r"(value) : : "memory"); } @@ -509,7 +515,7 @@ template inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value || (sizeof(Tp) > sizeof(Tp*))>::type - DoNotOptimize(Tp& value) { + DoNotOptimize(Tp&& value) { asm volatile("" : "+m"(value) : : "memory"); } @@ -526,7 +532,13 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { } template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize( +#ifdef BENCHMARK_HAS_CXX11 + Tp&& value +#else + Tp& value +#endif +) { asm volatile("" : "+m"(value) : : "memory"); } #endif diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc index 90d5af35fa..04ec9386a3 100644 --- a/test/donotoptimize_test.cc +++ b/test/donotoptimize_test.cc @@ -61,4 +61,9 @@ int main(int, char*[]) { // These tests are to e BitRef lval = BitRef::Make(); benchmark::DoNotOptimize(lval); + +#ifdef BENCHMARK_HAS_CXX11 + // Check that accept rvalue. + benchmark::DoNotOptimize(BitRef::Make()); +#endif } From b323288cbac5fd1dd35f153e767497a23c337742 Mon Sep 17 00:00:00 2001 From: Chilledheart Date: Mon, 19 Jun 2023 15:51:48 +0800 Subject: [PATCH 103/561] Fix a typo in regex choice (#1610) BENCHMARK_HAVE_STD_REGEX is not used but HAVE_STD_REGEX like the other two choices, i.e. HAVE_GNU_POSIX_REGEX and HAVE_POSIX_REGEX. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/re.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/re.h b/src/re.h index 630046782d..9afb869bea 100644 --- a/src/re.h +++ b/src/re.h @@ -33,7 +33,7 @@ // Prefer C regex libraries when compiling w/o exceptions so that we can // correctly report errors. #if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && \ - defined(BENCHMARK_HAVE_STD_REGEX) && \ + defined(HAVE_STD_REGEX) && \ (defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX)) #undef HAVE_STD_REGEX #endif From 1d25c2e3bea73ea03592abc7e7ef9b6a47c2e90b Mon Sep 17 00:00:00 2001 From: Gary Miguel Date: Wed, 21 Jun 2023 15:35:44 -0700 Subject: [PATCH 104/561] remove old-style (C-style) casts (#1614) Remove old-style (C-style) casts This is required by the Google C++ style guide: https://google.github.io/styleguide/cppguide.html#Casting --- BUILD.bazel | 4 ++++ CMakeLists.txt | 1 + src/benchmark.cc | 2 +- src/log.h | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 99616163e7..60d31d2f2e 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -49,6 +49,10 @@ cc_library( ":windows": ["-DEFAULTLIB:shlwapi.lib"], "//conditions:default": ["-pthread"], }), + copts = select({ + ":windows": [], + "//conditions:default": ["-Werror=old-style-cast"], + }), strip_include_prefix = "include", visibility = ["//visibility:public"], # Only static linking is allowed; no .so will be produced. diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a74e438d..f9d2ad7efe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,6 +175,7 @@ else() add_cxx_compiler_flag(-Wextra) add_cxx_compiler_flag(-Wshadow) add_cxx_compiler_flag(-Wfloat-equal) + add_cxx_compiler_flag(-Wold-style-cast) if(BENCHMARK_ENABLE_WERROR) add_cxx_compiler_flag(-Werror) endif() diff --git a/src/benchmark.cc b/src/benchmark.cc index f1633b703f..7fb1740af3 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -229,7 +229,7 @@ void State::PauseTiming() { for (const auto& name_and_measurement : measurements) { auto name = name_and_measurement.first; auto measurement = name_and_measurement.second; - BM_CHECK_EQ(std::fpclassify((double)counters[name]), FP_ZERO); + BM_CHECK_EQ(std::fpclassify(double{counters[name]}), FP_ZERO); counters[name] = Counter(measurement, Counter::kAvgIterations); } } diff --git a/src/log.h b/src/log.h index 45701667a2..9a21400b09 100644 --- a/src/log.h +++ b/src/log.h @@ -61,7 +61,7 @@ inline int& LogLevel() { } inline LogType& GetNullLogInstance() { - static LogType null_log((std::ostream*)nullptr); + static LogType null_log(static_cast(nullptr)); return null_log; } From aacf2b1af967b083565be8c7181626b4609318ac Mon Sep 17 00:00:00 2001 From: Andy Christiansen Date: Tue, 27 Jun 2023 14:03:39 +0200 Subject: [PATCH 105/561] Add support for bzlmod (excluding Python bindings) (#1615) * Migrate to bzlmod * Update Python version to PY3, as indicated by the actual source file. * Migrate more libraries & first draft of direct pywheel rule usage in Bazel * Integrate with nanobind and libpfm * Make Python toolchain a dev dependency * Undo py_wheel usage until later * Added support for bzlmod for C++ parts of google_benchmark. * Make //tools:all buildable with --enable_bzlmod --------- Co-authored-by: Andy Christiansen --- MODULE.bazel | 34 ++++++++++++++++++++++++++++++++++ WORKSPACE | 4 ++-- WORKSPACE.bzlmod | 2 ++ docs/releasing.md | 16 ++++++++++------ requirements.txt | 2 -- tools/BUILD.bazel | 2 +- tools/requirements.txt | 3 ++- 7 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 MODULE.bazel create mode 100644 WORKSPACE.bzlmod delete mode 100644 requirements.txt diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000000..0337ccca10 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,34 @@ +module(name = "com_github_google_benchmark", version="1.8.0") + +bazel_dep(name = "bazel_skylib", version = "1.4.1") +bazel_dep(name = "platforms", version = "0.0.6") +bazel_dep(name = "rules_foreign_cc", version = "0.9.0") +bazel_dep(name = "rules_cc", version = "0.0.6") +bazel_dep(name = "rules_python", version = "0.23.1") +bazel_dep(name = "googletest", version = "1.12.1", repo_name = "com_google_googletest") +bazel_dep(name = "libpfm", version = "4.11.0") + +# Register a toolchain for Python 3.9 to be able to build numpy. Python +# versions >=3.10 are problematic. +# A second reason for this is to be able to build Python hermetically instead +# of relying on the changing default version from rules_python. + +python = use_extension("@rules_python//python/extensions:python.bzl", "python") +python.toolchain(python_version = "3.9") + +# Extract the interpreter from the hermetic toolchain above, so we can use that +# instead of the system interpreter for the pip compiplation step below. +interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter") +interpreter.install( + name = "interpreter", + python_name = "python_3_9", +) +use_repo(interpreter, "interpreter") + +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") +pip.parse( + name="tools_pip_deps", + incompatible_generate_aliases = True, + python_interpreter_target="@interpreter//:python", + requirements_lock="//tools:requirements.txt") +use_repo(pip, "tools_pip_deps") diff --git a/WORKSPACE b/WORKSPACE index 74e7ebcbe9..833590f289 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -11,8 +11,8 @@ rules_foreign_cc_dependencies() load("@rules_python//python:pip.bzl", pip3_install="pip_install") pip3_install( - name = "py_deps", - requirements = "//:requirements.txt", + name = "tools_pip_deps", + requirements = "//tools:requirements.txt", ) new_local_repository( diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod new file mode 100644 index 0000000000..9526376d77 --- /dev/null +++ b/WORKSPACE.bzlmod @@ -0,0 +1,2 @@ +# This file marks the root of the Bazel workspace. +# See MODULE.bazel for dependencies and setup. diff --git a/docs/releasing.md b/docs/releasing.md index 6d3b6138cc..cdf415997a 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -8,13 +8,17 @@ * `git log $(git describe --abbrev=0 --tags)..HEAD` gives you the list of commits between the last annotated tag and HEAD * Pick the most interesting. -* Create one last commit that updates the version saved in `CMakeLists.txt` and the - `__version__` variable in `bindings/python/google_benchmark/__init__.py`to the release - version you're creating. (This version will be used if benchmark is installed from the - archive you'll be creating in the next step.) +* Create one last commit that updates the version saved in `CMakeLists.txt`, `MODULE.bazel` + and the `__version__` variable in `bindings/python/google_benchmark/__init__.py`to the + release version you're creating. (This version will be used if benchmark is installed + from the archive you'll be creating in the next step.) ``` -project (benchmark VERSION 1.6.0 LANGUAGES CXX) +project (benchmark VERSION 1.8.0 LANGUAGES CXX) +``` + +``` +module(name = "com_github_google_benchmark", version="1.8.0") ``` ```python @@ -22,7 +26,7 @@ project (benchmark VERSION 1.6.0 LANGUAGES CXX) # ... -__version__ = "1.6.0" # <-- change this to the release version you are creating +__version__ = "1.8.0" # <-- change this to the release version you are creating # ... ``` diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1c8a4bd123..0000000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -numpy == 1.22 -scipy == 1.5.4 diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index c0cbc64e27..d25caa79ae 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -1,4 +1,4 @@ -load("@py_deps//:requirements.bzl", "requirement") +load("@tools_pip_deps//:requirements.bzl", "requirement") py_library( name = "gbench", diff --git a/tools/requirements.txt b/tools/requirements.txt index 3b3331b5af..afbc596c15 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1 +1,2 @@ -scipy>=1.5.0 \ No newline at end of file +numpy == 1.25 +scipy == 1.5.4 From fed73374d7d2843f4197e76547349e54f180d312 Mon Sep 17 00:00:00 2001 From: Andy Christiansen Date: Mon, 3 Jul 2023 10:59:56 +0200 Subject: [PATCH 106/561] Add a CI test for the new bzlmod integration (#1617) * Test bzlmod build workflow for Bazel --------- Co-authored-by: Andy Christiansen --- .github/workflows/bazel.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 9e31c9012b..d61735aed0 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -5,14 +5,14 @@ on: pull_request: {} jobs: - job: - name: bazel.${{ matrix.os }} + build_and_test_default: + name: bazel.${{ matrix.os }}.${{ matrix.bzlmod && 'bzlmod' || 'no_bzlmod' }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-2022] - + bzlmod: [false, true] steps: - uses: actions/checkout@v3 @@ -28,8 +28,8 @@ jobs: - name: build run: | - bazel build //:benchmark //:benchmark_main //test/... + bazel build ${{ matrix.bzlmod && '--enable_bzlmod' || '--noenable_bzlmod' }} //:benchmark //:benchmark_main //test/... - name: test run: | - bazel test --test_output=all //test/... + bazel test ${{ matrix.bzlmod && '--enable_bzlmod' || '--noenable_bzlmod' }} --test_output=all //test/... From edb0d3d46d76df6c54c174f026c8a6a21b833ebf Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 3 Jul 2023 12:18:31 +0300 Subject: [PATCH 107/561] Suppress intentional potential memory leak as detected by clang static analysis (#1618) https://github.com/google/benchmark/issues/1513 Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- include/benchmark/benchmark.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 558aca8ddc..1444ec6168 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1362,6 +1362,8 @@ class LambdaBenchmark : public Benchmark { inline internal::Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn) { + // FIXME: this should be a `std::make_unique<>()` but we don't have C++14. + // codechecker_intentional [cplusplus.NewDeleteLeaks] return internal::RegisterBenchmarkInternal( ::new internal::FunctionBenchmark(name, fn)); } @@ -1371,6 +1373,8 @@ template internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { using BenchType = internal::LambdaBenchmark::type>; + // FIXME: this should be a `std::make_unique<>()` but we don't have C++14. + // codechecker_intentional [cplusplus.NewDeleteLeaks] return internal::RegisterBenchmarkInternal( ::new BenchType(name, std::forward(fn))); } From daa12bcc5a78e2f244d29e87a4408ff72516a5d9 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 4 Jul 2023 08:48:07 +0100 Subject: [PATCH 108/561] bump version to 1.8.1 pre release --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9d2ad7efe..c1b0374123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.10...3.22) -project (benchmark VERSION 1.8.0 LANGUAGES CXX) +project (benchmark VERSION 1.8.1 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 0337ccca10..505510de2d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,4 +1,4 @@ -module(name = "com_github_google_benchmark", version="1.8.0") +module(name = "com_github_google_benchmark", version="1.8.1") bazel_dep(name = "bazel_skylib", version = "1.4.1") bazel_dep(name = "platforms", version = "0.0.6") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index a118dad7e1..ebab5c28ab 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -69,7 +69,7 @@ def my_benchmark(state): "State", ] -__version__ = "1.8.0" +__version__ = "1.8.1" class __OptionMaker: From 408f9e06676ffdc226adf652e013aa15861589ad Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 4 Jul 2023 08:55:37 +0100 Subject: [PATCH 109/561] Add discord server link to README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index b64048b7d3..a5e5d392d8 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,9 @@ [![bazel](https://github.com/google/benchmark/actions/workflows/bazel.yml/badge.svg)](https://github.com/google/benchmark/actions/workflows/bazel.yml) [![pylint](https://github.com/google/benchmark/workflows/pylint/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Apylint) [![test-bindings](https://github.com/google/benchmark/workflows/test-bindings/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Atest-bindings) - -[![Build Status](https://travis-ci.org/google/benchmark.svg?branch=main)](https://travis-ci.org/google/benchmark) [![Coverage Status](https://coveralls.io/repos/google/benchmark/badge.svg)](https://coveralls.io/r/google/benchmark) +[![Discord](https://discordapp.com/api/guilds/1125694995928719494/widget.png?style=shield)](https://discord.gg/cz7UX7wKC2) A library to benchmark code snippets, similar to unit tests. Example: From 43b2917dce1ae9c5949d66dfc6baf8d04d359971 Mon Sep 17 00:00:00 2001 From: Chinmay Dalal Date: Tue, 4 Jul 2023 20:43:55 +0530 Subject: [PATCH 110/561] Add more terminals with color support (#1621) --- src/colorprint.cc | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/colorprint.cc b/src/colorprint.cc index 9a653c5007..0bfd67041d 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -163,12 +163,24 @@ bool IsColorTerminal() { #else // On non-Windows platforms, we rely on the TERM variable. This list of // supported TERM values is copied from Google Test: - // . + // . const char* const SUPPORTED_TERM_VALUES[] = { - "xterm", "xterm-color", "xterm-256color", - "screen", "screen-256color", "tmux", - "tmux-256color", "rxvt-unicode", "rxvt-unicode-256color", - "linux", "cygwin", + "xterm", + "xterm-color", + "xterm-256color", + "screen", + "screen-256color", + "tmux", + "tmux-256color", + "rxvt-unicode", + "rxvt-unicode-256color", + "linux", + "cygwin", + "xterm-kitty", + "alacritty", + "foot", + "foot-extra", + "wezterm", }; const char* const term = getenv("TERM"); From e730f91d8cb6af19a172d6a36b4279181a02a9ff Mon Sep 17 00:00:00 2001 From: Enrico Seiler Date: Wed, 5 Jul 2023 19:05:08 +0200 Subject: [PATCH 111/561] Fix passing non-const lvalue refs to DoNotOptimize (#1622) --- cmake/GoogleTest.cmake | 20 ++++++++++------ include/benchmark/benchmark.h | 44 ++++++++++++++++++++++++++--------- test/CMakeLists.txt | 5 ++++ 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/cmake/GoogleTest.cmake b/cmake/GoogleTest.cmake index 44adbfbe4b..e66e9d1a20 100644 --- a/cmake/GoogleTest.cmake +++ b/cmake/GoogleTest.cmake @@ -29,19 +29,25 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) include(${GOOGLETEST_PREFIX}/googletest-paths.cmake) -# googletest doesn't seem to want to stay build warning clean so let's not hurt ourselves. -if (MSVC) - add_compile_options(/wd4244 /wd4722) -else() - add_compile_options(-w) -endif() - # Add googletest directly to our build. This defines # the gtest and gtest_main targets. add_subdirectory(${GOOGLETEST_SOURCE_DIR} ${GOOGLETEST_BINARY_DIR} EXCLUDE_FROM_ALL) +# googletest doesn't seem to want to stay build warning clean so let's not hurt ourselves. +if (MSVC) + target_compile_options(gtest PRIVATE "/wd4244" "/wd4722") + target_compile_options(gtest_main PRIVATE "/wd4244" "/wd4722") + target_compile_options(gmock PRIVATE "/wd4244" "/wd4722") + target_compile_options(gmock_main PRIVATE "/wd4244" "/wd4722") +else() + target_compile_options(gtest PRIVATE "-w") + target_compile_options(gtest_main PRIVATE "-w") + target_compile_options(gmock PRIVATE "-w") + target_compile_options(gmock_main PRIVATE "-w") +endif() + if(NOT DEFINED GTEST_COMPILE_COMMANDS) set(GTEST_COMPILE_COMMANDS ON) endif() diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 1444ec6168..e3857e717f 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -465,19 +465,24 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { } template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize( -#ifdef BENCHMARK_HAS_CXX11 - Tp&& value +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { +#if defined(__clang__) + asm volatile("" : "+r,m"(value) : : "memory"); #else - Tp& value + asm volatile("" : "+m,r"(value) : : "memory"); #endif -) { +} + +#ifdef BENCHMARK_HAS_CXX11 +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { #if defined(__clang__) asm volatile("" : "+r,m"(value) : : "memory"); #else asm volatile("" : "+m,r"(value) : : "memory"); #endif } +#endif #elif defined(BENCHMARK_HAS_CXX11) && (__GNUC__ >= 5) // Workaround for a bug with full argument copy overhead with GCC. // See: #1340 and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105519 @@ -503,6 +508,22 @@ inline BENCHMARK_ALWAYS_INLINE asm volatile("" : : "m"(value) : "memory"); } +template +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value && + (sizeof(Tp) <= sizeof(Tp*))>::type + DoNotOptimize(Tp& value) { + asm volatile("" : "+m,r"(value) : : "memory"); +} + +template +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value || + (sizeof(Tp) > sizeof(Tp*))>::type + DoNotOptimize(Tp& value) { + asm volatile("" : "+m"(value) : : "memory"); +} + template inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value && @@ -532,16 +553,17 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { } template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize( +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { + asm volatile("" : "+m"(value) : : "memory"); +} + #ifdef BENCHMARK_HAS_CXX11 - Tp&& value -#else - Tp& value -#endif -) { +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { asm volatile("" : "+m"(value) : : "memory"); } #endif +#endif #ifndef BENCHMARK_HAS_CXX11 inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 78d6d51750..fd88131988 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -122,6 +122,11 @@ compile_benchmark_test(skip_with_error_test) add_test(NAME skip_with_error_test COMMAND skip_with_error_test --benchmark_min_time=0.01s) compile_benchmark_test(donotoptimize_test) +# Enable errors for deprecated deprecations (DoNotOptimize(Tp const& value)). +check_cxx_compiler_flag(-Werror=deprecated-declarations BENCHMARK_HAS_DEPRECATED_DECLARATIONS_FLAG) +if (BENCHMARK_HAS_DEPRECATED_DECLARATIONS_FLAG) + target_compile_options (donotoptimize_test PRIVATE "-Werror=deprecated-declarations") +endif() # Some of the issues with DoNotOptimize only occur when optimization is enabled check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) if (BENCHMARK_HAS_O3_FLAG) From 015d1a091af6937488242b70121858bce8fd40e9 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 6 Jul 2023 09:50:35 +0100 Subject: [PATCH 112/561] bump version to 1.8.2 ready for release --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1b0374123..ae89e06d9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.10...3.22) -project (benchmark VERSION 1.8.1 LANGUAGES CXX) +project (benchmark VERSION 1.8.2 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 505510de2d..46212429a6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,4 +1,4 @@ -module(name = "com_github_google_benchmark", version="1.8.1") +module(name = "com_github_google_benchmark", version="1.8.2") bazel_dep(name = "bazel_skylib", version = "1.4.1") bazel_dep(name = "platforms", version = "0.0.6") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index ebab5c28ab..2a5e65dba4 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -69,7 +69,7 @@ def my_benchmark(state): "State", ] -__version__ = "1.8.1" +__version__ = "1.8.2" class __OptionMaker: From 4931aefb51d1e5872b096a97f43e13fa0fc33c8c Mon Sep 17 00:00:00 2001 From: Andy Christiansen Date: Fri, 7 Jul 2023 10:58:16 +0200 Subject: [PATCH 113/561] Fix broken PFM-enabled tests (#1623) * Add pfm CI actions for bazel * Fix problems in unit test. * Undo enabling the CI tests for pfm - github CI machines seemingly do not support performance counters. * Remove commented code - can be revisited in github history when needed, and there's a comment explaining the rationale behind the new test code. --------- Co-authored-by: Andy Christiansen Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- test/perf_counters_gtest.cc | 53 +++++++++++++++++-------------------- test/perf_counters_test.cc | 9 +++++++ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index bb55aff7c5..250ceefadb 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -2,6 +2,7 @@ #include #include "../src/perf_counters.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" #ifndef GTEST_SKIP @@ -14,6 +15,9 @@ struct MsgHandler { using benchmark::internal::PerfCounters; using benchmark::internal::PerfCountersMeasurement; using benchmark::internal::PerfCounterValues; +using ::testing::AllOf; +using ::testing::Gt; +using ::testing::Lt; namespace { const char kGenericPerfEvent1[] = "CYCLES"; @@ -72,8 +76,7 @@ TEST(PerfCountersTest, NegativeTest) { { // Add a bad apple in the end of the chain to check the edges auto counter = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, - kGenericPerfEvent3, - "MISPREDICTED_BRANCH_RETIRED"}); + kGenericPerfEvent3, "bad event name"}); EXPECT_EQ(counter.num_counters(), 3); EXPECT_EQ(counter.names(), std::vector({kGenericPerfEvent1, kGenericPerfEvent2, @@ -257,10 +260,14 @@ TEST(PerfCountersTest, MultiThreaded) { static_cast(after[0] - before[0]), static_cast(after[1] - before[1])}; - // Some extra work will happen on the main thread - like joining the threads - // - so the ratio won't be quite 2.0, but very close. - EXPECT_GE(Elapsed4Threads[0], 1.9 * Elapsed2Threads[0]); - EXPECT_GE(Elapsed4Threads[1], 1.9 * Elapsed2Threads[1]); + // The following expectations fail (at least on a beefy workstation with lots + // of cpus) - it seems that in some circumstances the runtime of 4 threads + // can even be better than with 2. + // So instead of expecting 4 threads to be slower, let's just make sure they + // do not differ too much in general (one is not more than 10x than the + // other). + EXPECT_THAT(Elapsed4Threads[0] / Elapsed2Threads[0], AllOf(Gt(0.1), Lt(10))); + EXPECT_THAT(Elapsed4Threads[1] / Elapsed2Threads[1], AllOf(Gt(0.1), Lt(10))); } TEST(PerfCountersTest, HardwareLimits) { @@ -273,28 +280,18 @@ TEST(PerfCountersTest, HardwareLimits) { } EXPECT_TRUE(PerfCounters::Initialize()); - // Taken straight from `perf list` on x86-64 - // Got all hardware names since these are the problematic ones - std::vector counter_names{"cycles", // leader - "instructions", - "branches", - "L1-dcache-loads", - "L1-dcache-load-misses", - "L1-dcache-prefetches", - "L1-icache-load-misses", // leader - "L1-icache-loads", - "branch-load-misses", - "branch-loads", - "dTLB-load-misses", - "dTLB-loads", - "iTLB-load-misses", // leader - "iTLB-loads", - "branch-instructions", - "branch-misses", - "cache-misses", - "cache-references", - "stalled-cycles-backend", // leader - "stalled-cycles-frontend"}; + // Taken from `perf list`, but focusses only on those HW events that actually + // were reported when running `sudo perf stat -a sleep 10`. All HW events + // listed in the first command not reported in the second seem to not work. + // This is sad as we don't really get to test the grouping here (groups can + // contain up to 6 members)... + std::vector counter_names{ + "cycles", // leader + "instructions", // + "branches", // + "branch-misses", // + "cache-misses", // + }; // In the off-chance that some of these values are not supported, // we filter them out so the test will complete without failure diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index f0e9a17156..98cadda0b2 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -2,9 +2,16 @@ #include "../src/perf_counters.h" +#include "../src/commandlineflags.h" #include "benchmark/benchmark.h" #include "output_test.h" +namespace benchmark { + +BM_DECLARE_string(benchmark_perf_counters); + +} // namespace benchmark + static void BM_Simple(benchmark::State& state) { for (auto _ : state) { auto iterations = state.iterations(); @@ -24,5 +31,7 @@ int main(int argc, char* argv[]) { if (!benchmark::internal::PerfCounters::kSupported) { return 0; } + benchmark::FLAGS_benchmark_perf_counters = "CYCLES,BRANCHES"; + benchmark::internal::PerfCounters::Initialize(); RunOutputTests(argc, argv); } From b5aade18104abd60ba61e54b3b7affaa95c44a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=A6=E0=A5=87=E0=A4=B5=E0=A4=BE=E0=A4=82=E0=A4=B6=20?= =?UTF-8?q?=E0=A4=B5=E0=A4=BE=E0=A4=B0=E0=A5=8D=E0=A4=B7=E0=A5=8D=E0=A4=A3?= =?UTF-8?q?=E0=A5=87=E0=A4=AF?= Date: Sun, 9 Jul 2023 21:55:34 +0530 Subject: [PATCH 114/561] Update tools.md for missing color meaning issue #1491 (#1624) Update tools.md with more documentation about U-test Fixes https://github.com/google/benchmark/issues/1491 --- docs/tools.md | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/docs/tools.md b/docs/tools.md index f2d0c497f3..411f41d405 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -186,6 +186,146 @@ Benchmark Time CPU Time Old This is a mix of the previous two modes, two (potentially different) benchmark binaries are run, and a different filter is applied to each one. As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`. +### Note: Interpreting the output + +Performance measurements are an art, and performance comparisons are doubly so. +Results are often noisy and don't necessarily have large absolute differences to +them, so just by visual inspection, it is not at all apparent if two +measurements are actually showing a performance change or not. It is even more +confusing with multiple benchmark repetitions. + +Thankfully, what we can do, is use statistical tests on the results to determine +whether the performance has statistically-significantly changed. `compare.py` +uses [Mann–Whitney U +test](https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test), with a null +hypothesis being that there's no difference in performance. + +**The below output is a summary of a benchmark comparison with statistics +provided for a multi-threaded process.** +``` +Benchmark Time CPU Time Old Time New CPU Old CPU New +----------------------------------------------------------------------------------------------------------------------------- +benchmark/threads:1/process_time/real_time_pvalue 0.0000 0.0000 U Test, Repetitions: 27 vs 27 +benchmark/threads:1/process_time/real_time_mean -0.1442 -0.1442 90 77 90 77 +benchmark/threads:1/process_time/real_time_median -0.1444 -0.1444 90 77 90 77 +benchmark/threads:1/process_time/real_time_stddev +0.3974 +0.3933 0 0 0 0 +benchmark/threads:1/process_time/real_time_cv +0.6329 +0.6280 0 0 0 0 +OVERALL_GEOMEAN -0.1442 -0.1442 0 0 0 0 +``` +-------------------------------------------- +Here's a breakdown of each row: + +**benchmark/threads:1/process_time/real_time_pvalue**: This shows the _p-value_ for +the statistical test comparing the performance of the process running with one +thread. A value of 0.0000 suggests a statistically significant difference in +performance. The comparison was conducted using the U Test (Mann-Whitney +U Test) with 27 repetitions for each case. + +**benchmark/threads:1/process_time/real_time_mean**: This shows the relative +difference in mean execution time between two different cases. The negative +value (-0.1442) implies that the new process is faster by about 14.42%. The old +time was 90 units, while the new time is 77 units. + +**benchmark/threads:1/process_time/real_time_median**: Similarly, this shows the +relative difference in the median execution time. Again, the new process is +faster by 14.44%. + +**benchmark/threads:1/process_time/real_time_stddev**: This is the relative +difference in the standard deviation of the execution time, which is a measure +of how much variation or dispersion there is from the mean. A positive value +(+0.3974) implies there is more variance in the execution time in the new +process. + +**benchmark/threads:1/process_time/real_time_cv**: CV stands for Coefficient of +Variation. It is the ratio of the standard deviation to the mean. It provides a +standardized measure of dispersion. An increase (+0.6329) indicates more +relative variability in the new process. + +**OVERALL_GEOMEAN**: Geomean stands for geometric mean, a type of average that is +less influenced by outliers. The negative value indicates a general improvement +in the new process. However, given the values are all zero for the old and new +times, this seems to be a mistake or placeholder in the output. + +----------------------------------------- + + + +Let's first try to see what the different columns represent in the above +`compare.py` benchmarking output: + + 1. **Benchmark:** The name of the function being benchmarked, along with the + size of the input (after the slash). + + 2. **Time:** The average time per operation, across all iterations. + + 3. **CPU:** The average CPU time per operation, across all iterations. + + 4. **Iterations:** The number of iterations the benchmark was run to get a + stable estimate. + + 5. **Time Old and Time New:** These represent the average time it takes for a + function to run in two different scenarios or versions. For example, you + might be comparing how fast a function runs before and after you make some + changes to it. + + 6. **CPU Old and CPU New:** These show the average amount of CPU time that the + function uses in two different scenarios or versions. This is similar to + Time Old and Time New, but focuses on CPU usage instead of overall time. + +In the comparison section, the relative differences in both time and CPU time +are displayed for each input size. + + +A statistically-significant difference is determined by a **p-value**, which is +a measure of the probability that the observed difference could have occurred +just by random chance. A smaller p-value indicates stronger evidence against the +null hypothesis. + +**Therefore:** + 1. If the p-value is less than the chosen significance level (alpha), we + reject the null hypothesis and conclude the benchmarks are significantly + different. + 2. If the p-value is greater than or equal to alpha, we fail to reject the + null hypothesis and treat the two benchmarks as similar. + + + +The result of said the statistical test is additionally communicated through color coding: +```diff ++ Green: +``` + The benchmarks are _**statistically different**_. This could mean the + performance has either **significantly improved** or **significantly + deteriorated**. You should look at the actual performance numbers to see which + is the case. +```diff +- Red: +``` + The benchmarks are _**statistically similar**_. This means the performance + **hasn't significantly changed**. + +In statistical terms, **'green'** means we reject the null hypothesis that +there's no difference in performance, and **'red'** means we fail to reject the +null hypothesis. This might seem counter-intuitive if you're expecting 'green' +to mean 'improved performance' and 'red' to mean 'worsened performance'. +```bash + But remember, in this context: + + 'Success' means 'successfully finding a difference'. + 'Failure' means 'failing to find a difference'. +``` + + +Also, please note that **even if** we determine that there **is** a +statistically-significant difference between the two measurements, it does not +_necessarily_ mean that the actual benchmarks that were measured **are** +different, or vice versa, even if we determine that there is **no** +statistically-significant difference between the two measurements, it does not +necessarily mean that the actual benchmarks that were measured **are not** +different. + + + ### U test If there is a sufficient repetition count of the benchmarks, the tool can do From 16c6ad83aa46d01b0b12a32c8ed0360bb83d151b Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 10 Jul 2023 11:43:49 +0200 Subject: [PATCH 115/561] Add pyproject.toml file for PEP518 compliance (#1625) The newly created `pyproject.toml` contains all static metadata as well as the readme and version as dynamic arguments, to be read by setuptools during the build. What is left in the `setup.py` for now is the custom Bazel extension class, since that is not properly supported yet. --- pyproject.toml | 50 +++++++++++++++++++++++++++++++++++++++++++ setup.py | 57 ++------------------------------------------------ 2 files changed, 52 insertions(+), 55 deletions(-) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..fe8770bc78 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,50 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "google_benchmark" +description = "A library to benchmark code snippets." +requires-python = ">=3.8" +license = {file = "LICENSE"} +keywords = ["benchmark"] + +authors = [ + {name = "Google", email = "benchmark-discuss@googlegroups.com"}, +] + +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Software Development :: Testing", + "Topic :: System :: Benchmark", +] + +dynamic = ["readme", "version"] + +dependencies = [ + "absl-py>=0.7.1", +] + +[project.urls] +Homepage = "https://github.com/google/benchmark" +Documentation = "https://github.com/google/benchmark/tree/main/docs" +Repository = "https://github.com/google/benchmark.git" +Discord = "https://discord.gg/cz7UX7wKC2" + +[tool.setuptools] +package-dir = {"" = "bindings/python"} +zip-safe = false + +[tool.setuptools.packages.find] +where = ["bindings/python"] + +[tool.setuptools.dynamic] +version = { attr = "google_benchmark.__version__" } +readme = { file = "README.md", content-type = "text/markdown" } diff --git a/setup.py b/setup.py index 2388f59b9b..b02a6a7012 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,6 @@ import shutil import sysconfig from pathlib import Path -from typing import List import setuptools from setuptools.command import build_ext @@ -16,30 +15,6 @@ IS_MAC = platform.system() == "Darwin" -def _get_long_description(fp: str) -> str: - with open(fp, "r", encoding="utf-8") as f: - return f.read() - - -def _get_version(fp: str) -> str: - """Parse a version string from a file.""" - with open(fp, "r") as f: - for line in f: - if "__version__" in line: - delim = '"' - return line.split(delim)[1] - raise RuntimeError(f"could not find a version string in file {fp!r}.") - - -def _parse_requirements(fp: str) -> List[str]: - with open(fp) as requirements: - return [ - line.rstrip() - for line in requirements - if not (line.isspace() or line.startswith("#")) - ] - - @contextlib.contextmanager def temp_fill_include_path(fp: str): """Temporarily set the Python include path in a file.""" @@ -128,39 +103,11 @@ def bazel_build(self, ext: BazelExtension): setuptools.setup( - name="google_benchmark", - version=_get_version("bindings/python/google_benchmark/__init__.py"), - url="https://github.com/google/benchmark", - description="A library to benchmark code snippets.", - long_description=_get_long_description("README.md"), - long_description_content_type="text/markdown", - author="Google", - author_email="benchmark-py@google.com", - # Contained modules and scripts. - package_dir={"": "bindings/python"}, - packages=setuptools.find_packages("bindings/python"), - install_requires=_parse_requirements("bindings/python/requirements.txt"), cmdclass=dict(build_ext=BuildBazelExtension), ext_modules=[ BazelExtension( - "google_benchmark._benchmark", - "//bindings/python/google_benchmark:_benchmark", + name="google_benchmark._benchmark", + bazel_target="//bindings/python/google_benchmark:_benchmark", ) ], - zip_safe=False, - # PyPI package information. - classifiers=[ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Topic :: Software Development :: Testing", - "Topic :: System :: Benchmark", - ], - license="Apache 2.0", - keywords="benchmark", ) From 8805bd0c145586fa6b4ba783343329469ea1feaf Mon Sep 17 00:00:00 2001 From: Pichot Date: Tue, 11 Jul 2023 00:46:34 +0800 Subject: [PATCH 116/561] pfm: Use a more standard CMake approach for finding libpfm (#1628) * pfm: Use a more standard CMake approach for finding libpfm * add myself and sort AUTHORS & CONTRIBUTORS --- AUTHORS | 5 +++-- CONTRIBUTORS | 7 ++++--- cmake/Modules/FindPFM.cmake | 40 +++++++++++++++++-------------------- src/CMakeLists.txt | 4 ++-- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/AUTHORS b/AUTHORS index bafecaddb5..d08c1fdb87 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,6 +28,7 @@ Eric Backus Eric Fiselier Eugene Zhuk Evgeny Safronov +Fabien Pichot Federico Ficarelli Felix Homann Gergő Szitár @@ -47,14 +48,15 @@ Marcel Jacobse Matt Clarkson Maxim Vafin Mike Apodaca +Min-Yih Hsu MongoDB Inc. Nick Hutchinson Norman Heino Oleksandr Sochka Ori Livneh Paul Redmond -Raghu Raja Radoslav Yovchev +Raghu Raja Rainer Orth Roman Lebedev Sayan Bhattacharjee @@ -67,4 +69,3 @@ Tobias Schmidt Yixuan Qiu Yusuke Suzuki Zbigniew Skowron -Min-Yih Hsu diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 56f03e2d62..95bcad019b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -46,6 +46,7 @@ Eric Backus Eric Fiselier Eugene Zhuk Evgeny Safronov +Fabien Pichot Fanbo Meng Federico Ficarelli Felix Homann @@ -60,14 +61,15 @@ Joao Paulo Magalhaes John Millikin Jordan Williams Jussi Knuuttila -Kai Wolf Kaito Udagawa +Kai Wolf Kishan Kumar Lei Xu Marcel Jacobse Matt Clarkson Maxim Vafin Mike Apodaca +Min-Yih Hsu Nick Hutchinson Norman Heino Oleksandr Sochka @@ -76,8 +78,8 @@ Pascal Leroy Paul Redmond Pierre Phaneuf Radoslav Yovchev -Rainer Orth Raghu Raja +Rainer Orth Raul Marin Ray Glover Robert Guo @@ -91,4 +93,3 @@ Tom Madams Yixuan Qiu Yusuke Suzuki Zbigniew Skowron -Min-Yih Hsu diff --git a/cmake/Modules/FindPFM.cmake b/cmake/Modules/FindPFM.cmake index cf807a1ee9..0c480f5d8a 100644 --- a/cmake/Modules/FindPFM.cmake +++ b/cmake/Modules/FindPFM.cmake @@ -1,26 +1,22 @@ # If successful, the following variables will be defined: -# HAVE_LIBPFM. -# Set BENCHMARK_ENABLE_LIBPFM to 0 to disable, regardless of libpfm presence. -include(CheckIncludeFile) -include(CheckLibraryExists) -include(FeatureSummary) -enable_language(C) +# PFM_FOUND. +# PFM_LIBRARIES +# PFM_INCLUDE_DIRS +# the following target will be defined: +# PFM::libpfm -set_package_properties(PFM PROPERTIES - URL http://perfmon2.sourceforge.net/ - DESCRIPTION "a helper library to develop monitoring tools" - PURPOSE "Used to program specific performance monitoring events") +include(FindPackageHandleStandardArgs) -check_library_exists(libpfm.a pfm_initialize "" HAVE_LIBPFM_INITIALIZE) -if(HAVE_LIBPFM_INITIALIZE) - check_include_file(perfmon/perf_event.h HAVE_PERFMON_PERF_EVENT_H) - check_include_file(perfmon/pfmlib.h HAVE_PERFMON_PFMLIB_H) - check_include_file(perfmon/pfmlib_perf_event.h HAVE_PERFMON_PFMLIB_PERF_EVENT_H) - if(HAVE_PERFMON_PERF_EVENT_H AND HAVE_PERFMON_PFMLIB_H AND HAVE_PERFMON_PFMLIB_PERF_EVENT_H) - message("Using Perf Counters.") - set(HAVE_LIBPFM 1) - set(PFM_FOUND 1) - endif() -else() - message("Perf Counters support requested, but was unable to find libpfm.") +find_library(PFM_LIBRARY NAMES pfm) +find_path(PFM_INCLUDE_DIR NAMES perfmon/pfmlib.h) + +find_package_handle_standard_args(PFM REQUIRED_VARS PFM_LIBRARY PFM_INCLUDE_DIR) + +if (PFM_FOUND AND NOT TARGET PFM::libpfm) + add_library(PFM::libpfm UNKNOWN IMPORTED) + set_target_properties(PFM::libpfm PROPERTIES + IMPORTED_LOCATION "${PFM_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${PFM_INCLUDE_DIR}") endif() + +mark_as_advanced(PFM_LIBRARY PFM_INCLUDE_DIR) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 91ea5f42b2..daf82fb131 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,8 +29,8 @@ target_include_directories(benchmark PUBLIC ) # libpfm, if available -if (HAVE_LIBPFM) - target_link_libraries(benchmark PRIVATE pfm) +if (PFM_FOUND) + target_link_libraries(benchmark PRIVATE PFM::libpfm) target_compile_definitions(benchmark PRIVATE -DHAVE_LIBPFM) endif() From c30468bb4b92ccc3d790e45e0e720dc0d976e95a Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 10 Jul 2023 17:54:09 +0100 Subject: [PATCH 117/561] add back package properties for PFM --- cmake/Modules/FindPFM.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/Modules/FindPFM.cmake b/cmake/Modules/FindPFM.cmake index 0c480f5d8a..4bfe51ac48 100644 --- a/cmake/Modules/FindPFM.cmake +++ b/cmake/Modules/FindPFM.cmake @@ -7,6 +7,11 @@ include(FindPackageHandleStandardArgs) +set_package_properties(PFM PROPERTIES + URL http://perfmon2.sourceforge.net/ + DESCRIPTION "A helper library to develop monitoring tools" + PURPOSE "Used to program specific performance monitoring events") + find_library(PFM_LIBRARY NAMES pfm) find_path(PFM_INCLUDE_DIR NAMES perfmon/pfmlib.h) From a092f8222c1fa95986efe611abf78daba59d3c59 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 10 Jul 2023 17:58:01 +0100 Subject: [PATCH 118/561] missing cmake include --- cmake/Modules/FindPFM.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/Modules/FindPFM.cmake b/cmake/Modules/FindPFM.cmake index 4bfe51ac48..4c1ce938f9 100644 --- a/cmake/Modules/FindPFM.cmake +++ b/cmake/Modules/FindPFM.cmake @@ -5,6 +5,7 @@ # the following target will be defined: # PFM::libpfm +include(FeatureSummary) include(FindPackageHandleStandardArgs) set_package_properties(PFM PROPERTIES From cb39b7150d17df7bc54a214c1adf2a55b23f8f5e Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 11 Jul 2023 10:56:51 +0200 Subject: [PATCH 119/561] Bump `nanobind` to stable v1.4.0 tag (#1626) This seems to reduce binding sizes even further, with a wheel size of 175KB on my local machine (macOS 13.4.1). --- bazel/benchmark_deps.bzl | 3 +-- bindings/python/nanobind.BUILD | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index e9ca2cec5d..667065f9b7 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -48,8 +48,7 @@ def benchmark_deps(): new_git_repository( name = "nanobind", remote = "https://github.com/wjakob/nanobind.git", - commit = "1ffbfe836c9dac599496a170274ee0075094a607", # v0.2.0 - shallow_since = "1677873085 +0100", + tag = "v1.4.0", build_file = "@//bindings/python:nanobind.BUILD", recursive_init_submodules = True, ) diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD index 35536bba21..0c00b544ad 100644 --- a/bindings/python/nanobind.BUILD +++ b/bindings/python/nanobind.BUILD @@ -31,6 +31,7 @@ cc_library( "src/nb_internals.cpp", "src/nb_internals.h", "src/nb_ndarray.cpp", + "src/nb_static_property.cpp", "src/nb_type.cpp", "src/trampoline.cpp", ], From ba49f1c167b18d08414549d52e3135471b6ed741 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 18:28:32 +0300 Subject: [PATCH 120/561] Bump scipy from 1.5.4 to 1.10.0 in /tools (#1630) Bumps [scipy](https://github.com/scipy/scipy) from 1.5.4 to 1.10.0. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.5.4...v1.10.0) --- updated-dependencies: - dependency-name: scipy dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index afbc596c15..f32f35b8fb 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ numpy == 1.25 -scipy == 1.5.4 +scipy == 1.10.0 From e2556df80f1bcddfee9eba3a545e75ab99e40350 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:46:34 +0100 Subject: [PATCH 121/561] Downgrade bazel to windows-2019 (#1629) * Downgrade bazel to windows-2019 Windows 2022 is not well supported by bazel yet: https://github.com/bazelbuild/bazel/issues/18592 * no windows-latest, only windows-2019 (for bazel) --- .github/workflows/bazel.yml | 2 +- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index d61735aed0..53f6d3e6b1 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-2022] + os: [ubuntu-latest, macos-latest, windows-2019] bzlmod: [false, true] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 98fa7e1cac..e01bb7b014 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] + os: [ ubuntu-latest, macos-latest, windows-2019 ] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d3c4630e1a..5d0627266a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -33,7 +33,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-latest, windows-2019] steps: - name: Check out Google Benchmark From b1c4a752d123071241829f4d13f8533589f5145e Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Fri, 14 Jul 2023 13:56:01 +0100 Subject: [PATCH 122/561] Add tests for Human Readable functionality (#1632) * Add tests for Human Readable functionality also fix an issue where the SI/IEC unit wasn't being correctly passed through. --- src/string_util.cc | 48 ++++++++++++------------ src/string_util.h | 5 ++- test/output_test_helper.cc | 2 +- test/string_util_gtest.cc | 55 ++++++++++++++++++++++++++++ test/user_counters_thousands_test.cc | 32 ++++++++-------- 5 files changed, 99 insertions(+), 43 deletions(-) diff --git a/src/string_util.cc b/src/string_util.cc index 5e2d24a3cd..2dc7b18650 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -11,6 +11,7 @@ #include #include "arraysize.h" +#include "benchmark/benchmark.h" namespace benchmark { namespace { @@ -30,9 +31,8 @@ static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits), static const int64_t kUnitsSize = arraysize(kBigSIUnits); -void ToExponentAndMantissa(double val, double thresh, int precision, - double one_k, std::string* mantissa, - int64_t* exponent) { +void ToExponentAndMantissa(double val, int precision, double one_k, + std::string* mantissa, int64_t* exponent) { std::stringstream mantissa_stream; if (val < 0) { @@ -43,8 +43,8 @@ void ToExponentAndMantissa(double val, double thresh, int precision, // Adjust threshold so that it never excludes things which can't be rendered // in 'precision' digits. const double adjusted_threshold = - std::max(thresh, 1.0 / std::pow(10.0, precision)); - const double big_threshold = adjusted_threshold * one_k; + std::max(1.0, 1.0 / std::pow(10.0, precision)); + const double big_threshold = (adjusted_threshold * one_k) - 1; const double small_threshold = adjusted_threshold; // Values in ]simple_threshold,small_threshold[ will be printed as-is const double simple_threshold = 0.01; @@ -100,29 +100,14 @@ std::string ExponentToPrefix(int64_t exponent, bool iec) { return std::string(1, array[index]); } -std::string ToBinaryStringFullySpecified(double value, double threshold, - int precision, double one_k = 1024.0) { +std::string ToBinaryStringFullySpecified( + double value, int precision, Counter::OneK one_k = Counter::kIs1024) { std::string mantissa; int64_t exponent; - ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa, + ToExponentAndMantissa(value, precision, + one_k == Counter::kIs1024 ? 1024.0 : 1000.0, &mantissa, &exponent); - return mantissa + ExponentToPrefix(exponent, false); -} - -} // end namespace - -void AppendHumanReadable(int n, std::string* str) { - std::stringstream ss; - // Round down to the nearest SI prefix. - ss << ToBinaryStringFullySpecified(n, 1.0, 0); - *str += ss.str(); -} - -std::string HumanReadableNumber(double n, double one_k) { - // 1.1 means that figures up to 1.1k should be shown with the next unit down; - // this softens edge effects. - // 1 means that we should show one decimal place of precision. - return ToBinaryStringFullySpecified(n, 1.1, 1, one_k); + return mantissa + ExponentToPrefix(exponent, one_k == Counter::kIs1024); } std::string StrFormatImp(const char* msg, va_list args) { @@ -155,6 +140,19 @@ std::string StrFormatImp(const char* msg, va_list args) { return std::string(buff_ptr.get()); } +} // end namespace + +void AppendHumanReadable(int n, std::string* str) { + std::stringstream ss; + // Round down to the nearest SI prefix. + ss << ToBinaryStringFullySpecified(n, 0); + *str += ss.str(); +} + +std::string HumanReadableNumber(double n, Counter::OneK one_k) { + return ToBinaryStringFullySpecified(n, 1, one_k); +} + std::string StrFormat(const char* format, ...) { va_list args; va_start(args, format); diff --git a/src/string_util.h b/src/string_util.h index 37bdd2e980..b05281b9b4 100644 --- a/src/string_util.h +++ b/src/string_util.h @@ -6,15 +6,18 @@ #include #include +#include "benchmark/benchmark.h" #include "benchmark/export.h" #include "check.h" #include "internal_macros.h" namespace benchmark { +BENCHMARK_EXPORT void AppendHumanReadable(int n, std::string* str); -std::string HumanReadableNumber(double n, double one_k = 1024.0); +BENCHMARK_EXPORT +std::string HumanReadableNumber(double n, Counter::OneK one_k); BENCHMARK_EXPORT #if defined(__MINGW32__) diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index 241af5c916..25673700aa 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -45,7 +45,7 @@ SubMap& GetSubstitutions() { static SubMap map = { {"%float", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"}, // human-readable float - {"%hrfloat", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?[kMGTPEZYmunpfazy]?"}, + {"%hrfloat", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?[kKMGTPEZYmunpfazy]?i?"}, {"%percentage", percentage_re}, {"%int", "[ ]*[0-9]+"}, {" %s ", "[ ]+"}, diff --git a/test/string_util_gtest.cc b/test/string_util_gtest.cc index 8bfdb7a72c..7cf5749832 100644 --- a/test/string_util_gtest.cc +++ b/test/string_util_gtest.cc @@ -6,6 +6,7 @@ #include "../src/internal_macros.h" #include "../src/string_util.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" namespace { @@ -160,4 +161,58 @@ TEST(StringUtilTest, StrSplit) { std::vector({"hello", "there", "is", "more"})); } +using AppendHumanReadableFixture = + ::testing::TestWithParam>; + +INSTANTIATE_TEST_SUITE_P( + AppendHumanReadableTests, AppendHumanReadableFixture, + ::testing::Values(std::make_tuple(0, "0"), std::make_tuple(999, "999"), + std::make_tuple(1000, "1000"), + std::make_tuple(1024, "1Ki"), + std::make_tuple(1000 * 1000, "976\\.56.Ki"), + std::make_tuple(1024 * 1024, "1Mi"), + std::make_tuple(1000 * 1000 * 1000, "953\\.674Mi"), + std::make_tuple(1024 * 1024 * 1024, "1Gi"))); + +TEST_P(AppendHumanReadableFixture, AppendHumanReadable) { + std::string str; + benchmark::AppendHumanReadable(std::get<0>(GetParam()), &str); + ASSERT_THAT(str, ::testing::MatchesRegex(std::get<1>(GetParam()))); +} + +using HumanReadableFixture = ::testing::TestWithParam< + std::tuple>; + +INSTANTIATE_TEST_SUITE_P( + HumanReadableTests, HumanReadableFixture, + ::testing::Values( + std::make_tuple(0.0, benchmark::Counter::kIs1024, "0"), + std::make_tuple(999.0, benchmark::Counter::kIs1024, "999"), + std::make_tuple(1000.0, benchmark::Counter::kIs1024, "1000"), + std::make_tuple(1024.0, benchmark::Counter::kIs1024, "1Ki"), + std::make_tuple(1000 * 1000.0, benchmark::Counter::kIs1024, + "976\\.56.Ki"), + std::make_tuple(1024 * 1024.0, benchmark::Counter::kIs1024, "1Mi"), + std::make_tuple(1000 * 1000 * 1000.0, benchmark::Counter::kIs1024, + "953\\.674Mi"), + std::make_tuple(1024 * 1024 * 1024.0, benchmark::Counter::kIs1024, + "1Gi"), + std::make_tuple(0.0, benchmark::Counter::kIs1000, "0"), + std::make_tuple(999.0, benchmark::Counter::kIs1000, "999"), + std::make_tuple(1000.0, benchmark::Counter::kIs1000, "1k"), + std::make_tuple(1024.0, benchmark::Counter::kIs1000, "1.024k"), + std::make_tuple(1000 * 1000.0, benchmark::Counter::kIs1000, "1M"), + std::make_tuple(1024 * 1024.0, benchmark::Counter::kIs1000, + "1\\.04858M"), + std::make_tuple(1000 * 1000 * 1000.0, benchmark::Counter::kIs1000, + "1G"), + std::make_tuple(1024 * 1024 * 1024.0, benchmark::Counter::kIs1000, + "1\\.07374G"))); + +TEST_P(HumanReadableFixture, HumanReadableNumber) { + std::string str = benchmark::HumanReadableNumber(std::get<0>(GetParam()), + std::get<1>(GetParam())); + ASSERT_THAT(str, ::testing::MatchesRegex(std::get<2>(GetParam()))); +} + } // end namespace diff --git a/test/user_counters_thousands_test.cc b/test/user_counters_thousands_test.cc index a42683b32f..fc153835f8 100644 --- a/test/user_counters_thousands_test.cc +++ b/test/user_counters_thousands_test.cc @@ -16,13 +16,13 @@ void BM_Counters_Thousands(benchmark::State& state) { {"t0_1000000DefaultBase", bm::Counter(1000 * 1000, bm::Counter::kDefaults)}, {"t1_1000000Base1000", bm::Counter(1000 * 1000, bm::Counter::kDefaults, - benchmark::Counter::OneK::kIs1000)}, + bm::Counter::OneK::kIs1000)}, {"t2_1000000Base1024", bm::Counter(1000 * 1000, bm::Counter::kDefaults, - benchmark::Counter::OneK::kIs1024)}, + bm::Counter::OneK::kIs1024)}, {"t3_1048576Base1000", bm::Counter(1024 * 1024, bm::Counter::kDefaults, - benchmark::Counter::OneK::kIs1000)}, + bm::Counter::OneK::kIs1000)}, {"t4_1048576Base1024", bm::Counter(1024 * 1024, bm::Counter::kDefaults, - benchmark::Counter::OneK::kIs1024)}, + bm::Counter::OneK::kIs1024)}, }); } BENCHMARK(BM_Counters_Thousands)->Repetitions(2); @@ -30,21 +30,21 @@ ADD_CASES( TC_ConsoleOut, { {"^BM_Counters_Thousands/repeats:2 %console_report " - "t0_1000000DefaultBase=1000k " - "t1_1000000Base1000=1000k t2_1000000Base1024=976.56[23]k " - "t3_1048576Base1000=1048.58k t4_1048576Base1024=1024k$"}, + "t0_1000000DefaultBase=1M " + "t1_1000000Base1000=1M t2_1000000Base1024=976.56[23]Ki " + "t3_1048576Base1000=1.04858M t4_1048576Base1024=1Mi$"}, {"^BM_Counters_Thousands/repeats:2 %console_report " - "t0_1000000DefaultBase=1000k " - "t1_1000000Base1000=1000k t2_1000000Base1024=976.56[23]k " - "t3_1048576Base1000=1048.58k t4_1048576Base1024=1024k$"}, + "t0_1000000DefaultBase=1M " + "t1_1000000Base1000=1M t2_1000000Base1024=976.56[23]Ki " + "t3_1048576Base1000=1.04858M t4_1048576Base1024=1Mi$"}, {"^BM_Counters_Thousands/repeats:2_mean %console_report " - "t0_1000000DefaultBase=1000k t1_1000000Base1000=1000k " - "t2_1000000Base1024=976.56[23]k t3_1048576Base1000=1048.58k " - "t4_1048576Base1024=1024k$"}, + "t0_1000000DefaultBase=1M t1_1000000Base1000=1M " + "t2_1000000Base1024=976.56[23]Ki t3_1048576Base1000=1.04858M " + "t4_1048576Base1024=1Mi$"}, {"^BM_Counters_Thousands/repeats:2_median %console_report " - "t0_1000000DefaultBase=1000k t1_1000000Base1000=1000k " - "t2_1000000Base1024=976.56[23]k t3_1048576Base1000=1048.58k " - "t4_1048576Base1024=1024k$"}, + "t0_1000000DefaultBase=1M t1_1000000Base1000=1M " + "t2_1000000Base1024=976.56[23]Ki t3_1048576Base1000=1.04858M " + "t4_1048576Base1024=1Mi$"}, {"^BM_Counters_Thousands/repeats:2_stddev %console_time_only_report [ " "]*2 t0_1000000DefaultBase=0 t1_1000000Base1000=0 " "t2_1000000Base1024=0 t3_1048576Base1000=0 t4_1048576Base1024=0$"}, From c5997e0a78713859be412ad1e9d7e3e933b92fc6 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 17 Jul 2023 16:28:35 +0200 Subject: [PATCH 123/561] Delete unused requirements file, simplify nanobind build file (#1635) The dependencies are contained in the `pyproject.toml` since it was added. Switches to header and source file globbing instead of manually listing the files. The selects for different platforms are removed, as a tradeoff, we take a single- to low double-digit hit in wheel sizes (between 5 percent zipped and 12% installed on MacOS 13.4). --- bindings/python/nanobind.BUILD | 60 ++++++-------------------------- bindings/python/requirements.txt | 2 -- 2 files changed, 10 insertions(+), 52 deletions(-) delete mode 100644 bindings/python/requirements.txt diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD index 0c00b544ad..cd9faf99bb 100644 --- a/bindings/python/nanobind.BUILD +++ b/bindings/python/nanobind.BUILD @@ -1,57 +1,17 @@ - -config_setting( - name = "msvc_compiler", - flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"}, -) - cc_library( name = "nanobind", - hdrs = glob( - include = [ - "include/nanobind/*.h", - "include/nanobind/stl/*.h", - "include/nanobind/detail/*.h", + srcs = glob([ + "src/*.cpp" + ]), + copts = ["-fexceptions"], + includes = ["include", "ext/robin_map/include"], + textual_hdrs = glob( + [ + "include/**/*.h", + "src/*.h", + "ext/robin_map/include/tsl/*.h", ], - exclude = [], ), - srcs = [ - "include/nanobind/stl/detail/nb_dict.h", - "include/nanobind/stl/detail/nb_list.h", - "include/nanobind/stl/detail/traits.h", - "ext/robin_map/include/tsl/robin_map.h", - "ext/robin_map/include/tsl/robin_hash.h", - "ext/robin_map/include/tsl/robin_growth_policy.h", - "ext/robin_map/include/tsl/robin_set.h", - "src/buffer.h", - "src/common.cpp", - "src/error.cpp", - "src/implicit.cpp", - "src/nb_enum.cpp", - "src/nb_func.cpp", - "src/nb_internals.cpp", - "src/nb_internals.h", - "src/nb_ndarray.cpp", - "src/nb_static_property.cpp", - "src/nb_type.cpp", - "src/trampoline.cpp", - ], - copts = select({ - ":msvc_compiler": [], - "//conditions:default": [ - "-fexceptions", - "-Os", # size optimization - "-flto", # enable LTO - ], - }), - linkopts = select({ - "@com_github_google_benchmark//:macos": [ - "-undefined dynamic_lookup", - "-Wl,-no_fixup_chains", - "-Wl,-dead_strip", - ], - "//conditions:default": [], - }), - includes = ["include", "ext/robin_map/include"], deps = ["@python_headers"], visibility = ["//visibility:public"], ) diff --git a/bindings/python/requirements.txt b/bindings/python/requirements.txt deleted file mode 100644 index f5bbe7eca5..0000000000 --- a/bindings/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -absl-py>=0.7.1 - From 27d64a2351b98d48dd5b18c75ff536982a4ce26a Mon Sep 17 00:00:00 2001 From: James Sharpe Date: Tue, 18 Jul 2023 08:40:54 +0100 Subject: [PATCH 124/561] Update bzlmod support to new rules_python extension API (#1633) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- MODULE.bazel | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 46212429a6..459609d33a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,7 +4,7 @@ bazel_dep(name = "bazel_skylib", version = "1.4.1") bazel_dep(name = "platforms", version = "0.0.6") bazel_dep(name = "rules_foreign_cc", version = "0.9.0") bazel_dep(name = "rules_cc", version = "0.0.6") -bazel_dep(name = "rules_python", version = "0.23.1") +bazel_dep(name = "rules_python", version = "0.24.0") bazel_dep(name = "googletest", version = "1.12.1", repo_name = "com_google_googletest") bazel_dep(name = "libpfm", version = "4.11.0") @@ -16,19 +16,9 @@ bazel_dep(name = "libpfm", version = "4.11.0") python = use_extension("@rules_python//python/extensions:python.bzl", "python") python.toolchain(python_version = "3.9") -# Extract the interpreter from the hermetic toolchain above, so we can use that -# instead of the system interpreter for the pip compiplation step below. -interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter") -interpreter.install( - name = "interpreter", - python_name = "python_3_9", -) -use_repo(interpreter, "interpreter") - pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( - name="tools_pip_deps", - incompatible_generate_aliases = True, - python_interpreter_target="@interpreter//:python", + hub_name="tools_pip_deps", + python_version = "3.9", requirements_lock="//tools:requirements.txt") use_repo(pip, "tools_pip_deps") From 8f7b8dd9a3211e6043e742a383ccb35eb810829f Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 31 Jul 2023 11:51:37 +0200 Subject: [PATCH 125/561] Re-enable windows-latest tests for newer Bazel (#1641) The Windows toolchain detection fix made it into Bazel 6.3.0, so the CI should work again with the re-enabled `windows-latest` marker. Require Bazel 6.3.0 in the Linux container setup in `cibuildwheel`. --- .github/install_bazel.sh | 2 +- .github/workflows/bazel.yml | 2 +- .github/workflows/wheels.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/install_bazel.sh b/.github/install_bazel.sh index bb910d8b57..2b1f4e726c 100644 --- a/.github/install_bazel.sh +++ b/.github/install_bazel.sh @@ -5,7 +5,7 @@ if ! bazel version; then fi echo "Installing wget and downloading $arch Bazel binary from GitHub releases." yum install -y wget - wget "https://github.com/bazelbuild/bazel/releases/download/6.0.0/bazel-6.0.0-linux-$arch" -O /usr/local/bin/bazel + wget "https://github.com/bazelbuild/bazel/releases/download/6.3.0/bazel-6.3.0-linux-$arch" -O /usr/local/bin/bazel chmod +x /usr/local/bin/bazel else # bazel is installed for the correct architecture diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 53f6d3e6b1..1cdc38c97e 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-2019] + os: [ubuntu-latest, macos-latest, windows-latest] bzlmod: [false, true] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 5d0627266a..1f73bff4b2 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -46,7 +46,7 @@ jobs: platforms: all - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.12.0 + uses: pypa/cibuildwheel@v2.14.1 env: CIBW_BUILD: 'cp38-* cp39-* cp310-* cp311-*' CIBW_SKIP: "*-musllinux_*" From 71ad1856fd107877b3341d8f4db4588d0b3dea7d Mon Sep 17 00:00:00 2001 From: Saran Tunyasuvunakool Date: Mon, 31 Jul 2023 15:14:34 +0100 Subject: [PATCH 126/561] Fix `-Werror,-Wold-style-cast` build failure on Windows. (#1637) * Fix `-Werror,-Wold-style-cast` build failure on Windows. * Fix parentheses. --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/sysinfo.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 4578cb0fa5..416dca50b4 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -328,7 +328,7 @@ std::vector GetCacheSizesWindows() { using UPtr = std::unique_ptr; GetLogicalProcessorInformation(nullptr, &buffer_size); - UPtr buff((PInfo*)malloc(buffer_size), &std::free); + UPtr buff(static_cast(std::malloc(buffer_size)), &std::free); if (!GetLogicalProcessorInformation(buff.get(), &buffer_size)) PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ", GetLastError()); @@ -738,8 +738,8 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { SHGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "~MHz", nullptr, &data, &data_size))) - return static_cast((int64_t)data * - (int64_t)(1000 * 1000)); // was mhz + return static_cast(static_cast(data) * + static_cast(1000 * 1000)); // was mhz #elif defined(BENCHMARK_OS_SOLARIS) kstat_ctl_t* kc = kstat_open(); if (!kc) { From 6e80474e62181079236f8820f92bef445d02bbce Mon Sep 17 00:00:00 2001 From: Andy Christiansen Date: Mon, 31 Jul 2023 18:23:27 +0200 Subject: [PATCH 127/561] Mark internal deps as dev_depenencies so that downstream modules don't require those. (#1640) Co-authored-by: Andy Christiansen Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- MODULE.bazel | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 459609d33a..cf07c3ef5a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,11 +1,11 @@ -module(name = "com_github_google_benchmark", version="1.8.2") +module(name = "google_benchmark", version="1.8.2") bazel_dep(name = "bazel_skylib", version = "1.4.1") bazel_dep(name = "platforms", version = "0.0.6") bazel_dep(name = "rules_foreign_cc", version = "0.9.0") bazel_dep(name = "rules_cc", version = "0.0.6") -bazel_dep(name = "rules_python", version = "0.24.0") -bazel_dep(name = "googletest", version = "1.12.1", repo_name = "com_google_googletest") +bazel_dep(name = "rules_python", version = "0.24.0", dev_dependency = True) +bazel_dep(name = "googletest", version = "1.12.1", repo_name = "com_google_googletest", dev_dependency = True) bazel_dep(name = "libpfm", version = "4.11.0") # Register a toolchain for Python 3.9 to be able to build numpy. Python @@ -13,10 +13,10 @@ bazel_dep(name = "libpfm", version = "4.11.0") # A second reason for this is to be able to build Python hermetically instead # of relying on the changing default version from rules_python. -python = use_extension("@rules_python//python/extensions:python.bzl", "python") +python = use_extension("@rules_python//python/extensions:python.bzl", "python", dev_dependency = True) python.toolchain(python_version = "3.9") -pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) pip.parse( hub_name="tools_pip_deps", python_version = "3.9", From 02a354f3f323ae8256948e1dc77ddcb1dfc297da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=A6=E0=A5=87=E0=A4=B5=E0=A4=BE=E0=A4=82=E0=A4=B6=20?= =?UTF-8?q?=E0=A4=B5=E0=A4=BE=E0=A4=B0=E0=A5=8D=E0=A4=B7=E0=A5=8D=E0=A4=A3?= =?UTF-8?q?=E0=A5=87=E0=A4=AF?= Date: Tue, 1 Aug 2023 13:17:09 +0530 Subject: [PATCH 128/561] bug: Inconsistent suffixes console reporter 1009 (#1631) * removed appendHumanReadable as it was not used anywhere --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/string_util.cc | 27 +++++++++------------------ src/string_util.h | 3 --- test/string_util_gtest.cc | 21 +-------------------- 3 files changed, 10 insertions(+), 41 deletions(-) diff --git a/src/string_util.cc b/src/string_util.cc index 2dc7b18650..c69e40a813 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -15,13 +15,13 @@ namespace benchmark { namespace { - // kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta. -const char kBigSIUnits[] = "kMGTPEZY"; +const char* const kBigSIUnits[] = {"k", "M", "G", "T", "P", "E", "Z", "Y"}; // Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi. -const char kBigIECUnits[] = "KMGTPEZY"; +const char* const kBigIECUnits[] = {"Ki", "Mi", "Gi", "Ti", + "Pi", "Ei", "Zi", "Yi"}; // milli, micro, nano, pico, femto, atto, zepto, yocto. -const char kSmallSIUnits[] = "munpfazy"; +const char* const kSmallSIUnits[] = {"m", "u", "n", "p", "f", "a", "z", "y"}; // We require that all three arrays have the same size. static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits), @@ -92,16 +92,14 @@ std::string ExponentToPrefix(int64_t exponent, bool iec) { const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1); if (index >= kUnitsSize) return ""; - const char* array = + const char* const* array = (exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits); - if (iec) { - return array[index] + std::string("i"); - } - return std::string(1, array[index]); + + return std::string(array[index]); } -std::string ToBinaryStringFullySpecified( - double value, int precision, Counter::OneK one_k = Counter::kIs1024) { +std::string ToBinaryStringFullySpecified(double value, int precision, + Counter::OneK one_k) { std::string mantissa; int64_t exponent; ToExponentAndMantissa(value, precision, @@ -142,13 +140,6 @@ std::string StrFormatImp(const char* msg, va_list args) { } // end namespace -void AppendHumanReadable(int n, std::string* str) { - std::stringstream ss; - // Round down to the nearest SI prefix. - ss << ToBinaryStringFullySpecified(n, 0); - *str += ss.str(); -} - std::string HumanReadableNumber(double n, Counter::OneK one_k) { return ToBinaryStringFullySpecified(n, 1, one_k); } diff --git a/src/string_util.h b/src/string_util.h index b05281b9b4..731aa2c04c 100644 --- a/src/string_util.h +++ b/src/string_util.h @@ -13,9 +13,6 @@ namespace benchmark { -BENCHMARK_EXPORT -void AppendHumanReadable(int n, std::string* str); - BENCHMARK_EXPORT std::string HumanReadableNumber(double n, Counter::OneK one_k); diff --git a/test/string_util_gtest.cc b/test/string_util_gtest.cc index 7cf5749832..67b4bc0c24 100644 --- a/test/string_util_gtest.cc +++ b/test/string_util_gtest.cc @@ -1,5 +1,5 @@ //===---------------------------------------------------------------------===// -// statistics_test - Unit tests for src/statistics.cc +// string_util_test - Unit tests for src/string_util.cc //===---------------------------------------------------------------------===// #include @@ -161,25 +161,6 @@ TEST(StringUtilTest, StrSplit) { std::vector({"hello", "there", "is", "more"})); } -using AppendHumanReadableFixture = - ::testing::TestWithParam>; - -INSTANTIATE_TEST_SUITE_P( - AppendHumanReadableTests, AppendHumanReadableFixture, - ::testing::Values(std::make_tuple(0, "0"), std::make_tuple(999, "999"), - std::make_tuple(1000, "1000"), - std::make_tuple(1024, "1Ki"), - std::make_tuple(1000 * 1000, "976\\.56.Ki"), - std::make_tuple(1024 * 1024, "1Mi"), - std::make_tuple(1000 * 1000 * 1000, "953\\.674Mi"), - std::make_tuple(1024 * 1024 * 1024, "1Gi"))); - -TEST_P(AppendHumanReadableFixture, AppendHumanReadable) { - std::string str; - benchmark::AppendHumanReadable(std::get<0>(GetParam()), &str); - ASSERT_THAT(str, ::testing::MatchesRegex(std::get<1>(GetParam()))); -} - using HumanReadableFixture = ::testing::TestWithParam< std::tuple>; From 14961f1cb69edf47fb1b31986be01c554f36bc2c Mon Sep 17 00:00:00 2001 From: Ioanna-Maria Panagou <56998382+joannapng@users.noreply.github.com> Date: Thu, 10 Aug 2023 11:33:10 +0200 Subject: [PATCH 129/561] Fix IntelLLVM compiler error (#1644) * add -fno-finite-math-only for IntelLLVM --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae89e06d9f..68889a0f75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,11 +190,12 @@ else() # Disable warnings regarding deprecated parts of the library while building # and testing those parts of the library. add_cxx_compiler_flag(-Wno-deprecated-declarations) - if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") # Intel silently ignores '-Wno-deprecated-declarations', # warning no. 1786 must be explicitly disabled. # See #631 for rationale. add_cxx_compiler_flag(-wd1786) + add_cxx_compiler_flag(-fno-finite-math-only) endif() # Disable deprecation warnings for release builds (when -Werror is enabled). if(BENCHMARK_ENABLE_WERROR) @@ -205,7 +206,7 @@ else() endif() if (HAVE_CXX_FLAG_FSTRICT_ALIASING) - if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") #ICC17u2: Many false positives for Wstrict-aliasing + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") #ICC17u2: Many false positives for Wstrict-aliasing add_cxx_compiler_flag(-Wstrict-aliasing) endif() endif() @@ -270,7 +271,8 @@ if (BENCHMARK_USE_LIBCXX) if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") add_cxx_compiler_flag(-stdlib=libc++) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR - "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM") add_cxx_compiler_flag(-nostdinc++) message(WARNING "libc++ header path must be manually specified using CMAKE_CXX_FLAGS") # Adding -nodefaultlibs directly to CMAKE__LINKER_FLAGS will break From cbecc8ffc774d22b59d7ca2073827246807a5805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Devansh=20Varshney=20=28=E0=A4=A6=E0=A5=87=E0=A4=B5?= =?UTF-8?q?=E0=A4=BE=E0=A4=82=E0=A4=B6=20=E0=A4=B5=E0=A4=BE=E0=A4=B0?= =?UTF-8?q?=E0=A5=8D=E0=A4=B7=E0=A5=8D=E0=A4=A3=E0=A5=87=E0=A4=AF=29?= Date: Fri, 11 Aug 2023 15:29:53 +0530 Subject: [PATCH 130/561] fix: added benchmark_counters_tabular for file (#1645) * fix: added benchmark_counters_tabular for file * fix: only checking the counters_tabular flag --- src/benchmark.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 7fb1740af3..3e9c7f9642 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -575,7 +575,9 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, } if (!file_reporter) { default_file_reporter = internal::CreateReporter( - FLAGS_benchmark_out_format, ConsoleReporter::OO_None); + FLAGS_benchmark_out_format, FLAGS_benchmark_counters_tabular + ? ConsoleReporter::OO_Tabular + : ConsoleReporter::OO_None); file_reporter = default_file_reporter.get(); } file_reporter->SetOutputStream(&output_file); From 1c64a36c5b8ee75d462b3fe7a9d020c66a2a1094 Mon Sep 17 00:00:00 2001 From: Mircea Trofin Date: Fri, 11 Aug 2023 04:46:36 -0700 Subject: [PATCH 131/561] [perf-counters] Fix pause/resume (#1643) * [perf-counters] Fix pause/resume Using `state.PauseTiming() / state.ResumeTiming()` was broken. Thanks [@virajbshah] for the the repro testcase. * ran clang-format over the whole perf_counters_test.cc * Remove check that perf counters are 0 on `Pause`, since `Pause`/`Resume` sequences would cause a non-0 counter value * both upper and lower bound for the with/without resume counters --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/benchmark.cc | 3 +- test/perf_counters_test.cc | 67 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 3e9c7f9642..a4fd2e92e9 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -229,8 +229,7 @@ void State::PauseTiming() { for (const auto& name_and_measurement : measurements) { auto name = name_and_measurement.first; auto measurement = name_and_measurement.second; - BM_CHECK_EQ(std::fpclassify(double{counters[name]}), FP_ZERO); - counters[name] = Counter(measurement, Counter::kAvgIterations); + counters[name] += Counter(measurement, Counter::kAvgIterations); } } } diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index 98cadda0b2..5419947fff 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -1,8 +1,8 @@ +#include #undef NDEBUG -#include "../src/perf_counters.h" - #include "../src/commandlineflags.h" +#include "../src/perf_counters.h" #include "benchmark/benchmark.h" #include "output_test.h" @@ -21,17 +21,78 @@ static void BM_Simple(benchmark::State& state) { BENCHMARK(BM_Simple); ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Simple\",$"}}); +const int kIters = 1000000; + +void BM_WithoutPauseResume(benchmark::State& state) { + int n = 0; + + for (auto _ : state) { + for (auto i = 0; i < kIters; ++i) { + n = 1 - n; + benchmark::DoNotOptimize(n); + } + } +} + +BENCHMARK(BM_WithoutPauseResume); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_WithoutPauseResume\",$"}}); + +void BM_WithPauseResume(benchmark::State& state) { + int m = 0, n = 0; + + for (auto _ : state) { + for (auto i = 0; i < kIters; ++i) { + n = 1 - n; + benchmark::DoNotOptimize(n); + } + + state.PauseTiming(); + for (auto j = 0; j < kIters; ++j) { + m = 1 - m; + benchmark::DoNotOptimize(m); + } + state.ResumeTiming(); + } +} + +BENCHMARK(BM_WithPauseResume); + +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_WithPauseResume\",$"}}); + static void CheckSimple(Results const& e) { CHECK_COUNTER_VALUE(e, double, "CYCLES", GT, 0); CHECK_COUNTER_VALUE(e, double, "BRANCHES", GT, 0.0); } + +double withoutPauseResumeInstrCount = 0.0; +double withPauseResumeInstrCount = 0.0; + +static void CheckInstrCount(double* counter, Results const& e) { + BM_CHECK_GT(e.NumIterations(), 0); + *counter = e.GetAs("INSTRUCTIONS") / e.NumIterations(); +} + +static void CheckInstrCountWithoutResume(Results const& e) { + CheckInstrCount(&withoutPauseResumeInstrCount, e); +} + +static void CheckInstrCountWithResume(Results const& e) { + CheckInstrCount(&withPauseResumeInstrCount, e); +} + CHECK_BENCHMARK_RESULTS("BM_Simple", &CheckSimple); +CHECK_BENCHMARK_RESULTS("BM_WithoutPauseResume", &CheckInstrCountWithoutResume); +CHECK_BENCHMARK_RESULTS("BM_WithPauseResume", &CheckInstrCountWithResume); int main(int argc, char* argv[]) { if (!benchmark::internal::PerfCounters::kSupported) { return 0; } - benchmark::FLAGS_benchmark_perf_counters = "CYCLES,BRANCHES"; + benchmark::FLAGS_benchmark_perf_counters = "CYCLES,BRANCHES,INSTRUCTIONS"; benchmark::internal::PerfCounters::Initialize(); RunOutputTests(argc, argv); + + BM_CHECK_GT(withPauseResumeInstrCount, kIters); + BM_CHECK_GT(withoutPauseResumeInstrCount, kIters); + BM_CHECK_LT(withPauseResumeInstrCount, 1.5 * withoutPauseResumeInstrCount); } From aa59d40f8822358d012e854488c2e52857b8a1f0 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Mon, 14 Aug 2023 18:02:42 +0200 Subject: [PATCH 132/561] sysinfo.cc: Call getloadavg for Android API >= 29 (#1) (#1649) Support for `getloadavg` was added in API level 29. --- src/sysinfo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 416dca50b4..922e83ac92 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -817,7 +817,7 @@ std::vector GetLoadAvg() { #if (defined BENCHMARK_OS_FREEBSD || defined(BENCHMARK_OS_LINUX) || \ defined BENCHMARK_OS_MACOSX || defined BENCHMARK_OS_NETBSD || \ defined BENCHMARK_OS_OPENBSD || defined BENCHMARK_OS_DRAGONFLY) && \ - !defined(__ANDROID__) + !(defined(__ANDROID__) && __ANDROID_API__ < 29) static constexpr int kMaxSamples = 3; std::vector res(kMaxSamples, 0.0); const int nelem = getloadavg(res.data(), kMaxSamples); From 885e9f71d677f57fe409016e0a41e3a8b3ca0be1 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 17 Aug 2023 16:41:17 +0200 Subject: [PATCH 133/561] benchmark.cc: Fix benchmarks_with_threads condition (#1651) Change condition for `benchmarks_with_threads` from `benchmark.threads() > 0` to `> 1`. `threads()` appears to always be `>= 1`. Introduced in fbc6efa (Refactoring of PerfCounters infrastructure (#1559)) --- src/benchmark.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index a4fd2e92e9..974cde6cf4 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -383,7 +383,7 @@ void RunBenchmarks(const std::vector& benchmarks, BenchmarkReporter::PerFamilyRunReports* reports_for_family = nullptr; if (benchmark.complexity() != oNone) reports_for_family = &per_family_reports[benchmark.family_index()]; - benchmarks_with_threads += (benchmark.threads() > 0); + benchmarks_with_threads += (benchmark.threads() > 1); runners.emplace_back(benchmark, &perfcounters, reports_for_family); int num_repeats_of_this_instance = runners.back().GetNumRepeats(); num_repetitions_total += num_repeats_of_this_instance; From 72938cc1c52dddf9031aadc382a55839e7011fc7 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 21 Aug 2023 14:20:29 +0100 Subject: [PATCH 134/561] adding a logo to the docs --- README.md | 1 + docs/assets/images/icon.png | Bin 0 -> 11106 bytes docs/assets/images/icon.xcf | Bin 0 -> 25934 bytes docs/index.md | 1 + 4 files changed, 2 insertions(+) create mode 100644 docs/assets/images/icon.png create mode 100644 docs/assets/images/icon.xcf diff --git a/README.md b/README.md index a5e5d392d8..2f9c3e45e5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +![logo](assets/images/icon.png) # Benchmark [![build-and-test](https://github.com/google/benchmark/workflows/build-and-test/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Abuild-and-test) diff --git a/docs/assets/images/icon.png b/docs/assets/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b98260486e421e2f1caad425148160910778639e GIT binary patch literal 11106 zcmch7^;?u*^z8sD-6bWcNJvXJNJvVDfPg3Vm%GMl#V2SdL5?APuqU|)%>bze@piAV`qn@^zedj|Rj$9#; zb+9g-3g^XZCVa*4h@3?O$G^|3))$ebB|#+&SbhPGO+u_q3U9BJaX8Gxg|@q!y(635 z1Jt>A2iL>VlI>H9WQ_)1=yj&+UE_X3}LbRiXXifMhT z=em6SNGoJm@meg`3o%_`2dD8qo$=4i{?E7zD%f4pR#`~&zmYJ8sjJIjn@@&~6vvp| zmOI-exFnw7ic-F`ww9HOpMg_qBQ_iy&e!m4F(@ZERHraF-2;}GWdzLi_D0F}JQpwCwX)*k&7=F; z7&{F5rb-~J*6({_(9)v+y548J^LJay+uhK6de8oBHA&wq7JeC_~%8z8>C%jH% zn*HGiwxhxm7X*Uv8S0HzC|O_yA7Z*Hs>)&h#v;eZClmaj9fv?LAQWY#wLPY{<~+6a z%rDz_LzDgZ`Nvr8$cT?$E3@3WpPOxJot@Yio1FhlsXTAet-6YboZpJ3YQS#RkyWmP zpI<{+edG zVZ-*smBjt~O0!-YWyp9#d*Y*c?~2B)`We|Ykyn@dzqhwJKex05cPzbhUGP0x8Qnv4 zqTMJdE!`jN>k~;!OXH}nsgd*ZYh__)Cu3Gi=X>EF9v&{c(CQ0Ah*VPq$T^A|i(AdOJ1|w@sGUK|ybw z0+0dg_gPt^n%#FOtgNh%?SUA`jf%GVIUcu-aaGsNNsTulA>rF|&7}WeQWMeX>74F6 z^Bnc|bN3H-7IvJw>2KZQY_uuGu&N<{SpK3OBA_=PBM`crm@U_REG%U4T>r@$ehsljC+sZiwmq8^HU8Du@5CJE8p19%F0Qll z+c)m&X<1v_(sz-O1qz75PYnxxDZ@YW4eG4#NuF);hF=RPR#sMyxxBo5m&xfo+EiQ1 z7gZQaUU?@kkV!R}@fQ;L5{t6h>%e-qgHSSz=XuvhZ$x>$@0r`$*4AKAEw1}WK)c(4Kln#mhnzkd{|a;4(_ZKT@K{#mW1{QS5O+P%tiKAKbg~ zC(qg08E$CDZCZj*M|XG1SL;8CUu}$&quxhz?ir20)4d^_XPvs~kQM$HHpg*S+bIsM zimedpsBkYVEhSr7S<$-?PJ67Oug`*miyJ(;=9+Y9J6&6(prk|s(YegRLf}S3N5_%C z`P6#m7cKz-1uAa;Cw8;tA}F%`E>8Q9EL>b_eisK5cSJ=EUszg3RJ2_hq>8-itKUjX zOk}x%Pc55{uB&5gEHQ1*R_NvB)d!<`-RC_Y-4b$aubub`+fFLzFwf2m+bkm^W9Ob^ zHD3B;HWX3HA}MKddU7&l#(;x^6CJ~(8eLRW6o2bubWF@ju42rKf2)Ib!(1JqgauLv z-Mvmq69qLjHDyAv7Vo3@65X=sxVX4hx6K?<=EprxYAkvopOlZZJUoQ1qgTF$W$3$Q zu8o(a7`6I*vcvs)u)Mn3w>DbPFaMtUN%aCcI{FJmMQk~A?h@G4C-$aACT*>$d{!hT z_s=r+_g#g(_FwiN@G#!f({rEIlmeH6y>b9SLPf=Tw6idT(8R~a#(u!S&`xq;SYa%l6c;CVg)W~W z>Rx{D#`}VFFQs%b&uHl!3IT_C+qX26u-*h=Vc~uL_Pku0A+iU&yi_cFwUDKwl-RKT zq?8opHjLu3CpBF^gJkse6IImIEFFIgN8eL^(c*QW;!F5C5)%!_Znkl_7ULnLzWKw4 z=oqgbY85=@w-e*DpVdznb^qXj*sr%7x;0904L&y~;#M#=PRAo86x{MA+9%4)dEWh@ zH#U}R^q#+h0+t|y>Kz^)4FY(oX!Dg%Ke_yl-e+=I`WhTA z9dsj!Q#U&&=PkLE&DKnVpiVaC_3ORAx+7yYnKI-O?ec|PR#nVy{7`E1yHJT+tY|&G zk8MwUa&l4)H_Q*usI!?Mk(9C^34ha}Tq>+NQk(jFIB-Ew+WH|CC}N=8AEyjm0kcoF_ub$Mka$s#Skr$+&aQ&>J; zW|(p(aKU>=oMbZO&Ye3d#3of$Ro^Jpb$)fd=aoa+&woz(R#ydi^_|SA-hIayiPuQQ z>(g5X(Y*I}se`c;*W=%yAbzAEpyakBLeLpjjFUsD`EPH}%*u|k2B4z@SN7`i;;rza zm)F6%`ODXPMUN)TL(~SUP47D5LooC5@uUbkd|yxE{EnBvhl_&~CcTK0lOgUfl8YUT z_7LkfAe+@oc6nJ@qR@77h;o7bTNqpoOGgry$IoSOzZL70ggt8SNeR4l>(=b^cK$N` zs;@uX=~2)k&DCxm7az|Q5*$nw|HdZ>O>l4A(1D5~MNRyGtO|RA-|QP!N3_Gy_8cR< zz4hi~)i;*R5j_)MbNvwxqsEW9GI0lMqurIve_r}FrvCV$E<>_Se|3zB9cs;MUDbN> z?>A|MBOSf(e$?%^u#InP zW4tUR^`}azP*e={q=}JH>TT@!s3_^zS>yRCNoES?dp-QNLt&5feh;QRGLz;_6Lr_U z)dBI(9P-R$v_MTSU0d91pP?wTh}ZIa55(h2RVqY3dxzhBHa1@!W^IUmc2?HgS(%>> zHYV7(2-GA_7_0EkJh$p5Vwp$dISdt;{#f*UyxsR)L{u~-F{H&Y{(3Vj2Zt)Hgiqs0 z<1H}{ZYTUR^%i-2+yv=3of6&MWfFBQV`F2b7|WHuI7Y%)jh5x}e?yXLJ{_mpT)lGu z;3SwzE5CoUWr%C*>Yk45Ro23Ou&E{w45)--#HNUOR*wipMnv5G{_N@5;g(i1cg~|o zre~%%-QC^ItL7`8$(YfN^Sl00&+80yr#59AGl`sOdd0R&uu%m3LMMp@R?4Vh+6Y)? z&a=?qU}AP_oRpq^sEOB6SW!_?$&#=Wid`%2r%nRQDxVW)^O?P)BW7z;oJh&bM#E;e ztynvU&Tw)*k=zqn}HFnuXs@HlNYncs#fl1?udnBe6n#p9O&GNz!~6%luez{M;b;q0 zMLfK{Cr+bBM)H*3KG0SKRw(50*R*V?3zL9W!6{&aJQM?yfMx1&g>ehtNg7n7Y&<13 zCg1}p;dv`MD|c83@^N~?!om!$y1L%em@6saXoTE1{OnQ1)HYgUsdn$IUz3^)GvPh~ zkf@R6Pye9G5kD&&Rt%lYd|Oq((kw0h^F;!q=pxre=*hJZQJNx;oaj z0D!#i@;!h*>C?ih<>ePvAwsQ5pFfL^Yg1qkKUQCi}>^Ky;YT4 zR5+61&5z|>Lv>meNteRH!XMdTiUp&Ju324fz<4(n{>-;DN1qWG8DtCH-2R>6KkiFo zz%EWiM6~F(|3{l>bmhrt{ld($2m(HaRo1Y^JuUYIEgq4C`+X zl-=~SwOyNcTF+b;9-EqG!cGCrDfvD%>OU&{^^kHK zk7RVnLSvZKMzY8-f02=qF_y3p0DEe>5V#)nFw^q3I^9rPzp6+Q(lix{(r~^i&0NDT zN1<8mTa<8t=>gIaf^2DZRsOdY?Yk`GjfyAR`0Cs&*L3d_JjBv4GGZ4O6DuSl!#vPd zd78p!Wj4KnV7W>5I{EM3o^y=m`emWjvuC%ZA3AY|gfEU-PvPO*2yRzF<$$w`3y1&S zjqncsG)ez-q|}#8qC~!Oon>Ygf(gJTd8bTMbu1O?3E+Y6^2sot1C8Hk#RmqFu;$TB ziKoYLZ34NqrRo&m8xe%_o|@lzt$?G{0A?nr+hG4R9AmR6H&?b;N?A`eL&7&V32H`A zYja?3F5}$U;!-GmKA~+Fi4B`o)y?@q4-XF_d>tZU;@d#;U|{4?lmxFo+y66cw*Iq-EX<}*tKh@-Orz@>3BIb6`c6TH--s`b z|Jlq!Sja}tz(6cS5@k|SQvUpq)oA`(_;)h;E~fi}Zv%%j8Cj_0$&mkL&Y6IH+l5>9 z5;fFMR=7uJ60aqDRU4abDbdqrH(-fzt^4y8RZokK1oRExB28zIfBmnH{AD}n*^NKz zAO0Eca6W4RHZ)xIyn8e_IC$XB8=`~tv1XGUJ2G*0r6GZ9d&v=|W06qw{D0nH#G!$Pj8#5^if1?-YnB6DB|uVG?F02x(hK!{R=8alM- z9N7UQomvUXDlKK_lj5vS_X4 zJr%D7ck;s)D4ugBSA@8@F1`H(8xs`?<@vBRdtZZb$;(H&p{6u76g4-CCTt}NPr9rw zhC6t4b$9opVcck(b)pyZP=E90&1^zS$_5F>G*p_xGXan3NTewid0>Ir1rslopnYnp zkW+U5jZ0wIa$a6d$51uwOc=CFy=9#OZUep7kJFKXV*c@X@DaW5i;Y%5$mVUk$yQ%) zPBtDF^`Y+WP-YcAb;t+9273;7AVR0U_#jD!B(FY4+u`35n;efgEIJO)4)45>a^hA2 z{%MC923tr4h~9d-&ZfNSASV}`2qo|FkNePM?_>g{-Od|O;SRwMT?h%^v1n+ z?_T}pGM%VfPe1@-$yFrImh1lg;_)`8m6}Q@u=ZQibz0R6$_bq0#Kgq)Y(&3@GA4X! z;K8&ZI=>Lz&o6`csNY!3Q%>j$3&S#>N#S`O@@J~1AiwRTmpP*psNCD)hxb8UyxW(=ox$tWo!fG3C9&D1|>mEv=lH#)K_+@w*bEl2+P^*my&VZN`w{}JS7 zhx1@Ee_#FD&JLG={p{qQzBWBw>wk7hk`zgg(?mYOj2>HgAFhun4`fI#j9fQ6*<1Oq zXmBTgtwc;*Jh3w|F;ON&FHp;f2Uu5HAO^Xb;D28Dz4BQH-^mt?H?EPi7)Z=Ie;SsU zcvHEn>q`)(=Oe7c!;{|`q|1U-*Tlrd;|P;O3FuC>Qsm_2t@ma?E=_DjLNeZ$9ET9p z=ait}G9GABsys5kr!zVZ(!Kw>m!@X4?L>Lno*F+;_b0VB6W_Ni5`t=*O832SDLGxW zF0e;|6h?gfNaVR9|A`!wE1(~Ff{(OQqlT0EUc9TWZhW2yw}gbT#Np)gz6Mc;d9h)j zFAeJi>tjwe-jqP5oNdO6<3@fx2BCNR_HAiY4t`TaRf_GIzXu2AjCn#gl{=+O;{?Nk ziOkNAcSG3IkNVgu!hri2HR$_aT^uzH(UwDyHv^h$dYuD(ApuTI3NkmJiwGDlgciz? z$mQ16){fntP&2H3`Rpz4SHJ?AYK5md<;^yAWw&KQw2QdFa(Yrb)b2I~OzMc%w6tN~ zOIfipAt51Bz=kF^Hns;ClFW^-p|`vWm4X6vXG*?nQi!^3a+gXaz8Y@5j!VHJd>nJIjZBQz8X31hxQwlb`d^(bgph}6{NDY-|xWV2@;NH9YSo=rAh;J5lLFRbyi!j1+SH^D#P;Uc|L9OPZdT_}QO! z0q5l&YPu_+to(D4pFe-5KI#DM!+)Z=d_=)v@IryM$V(xR7&|}v&foW^ll@aQmgYb? zvM>znT0;&;l)0>$xF!smi$q$__mr*p#v+^Sr)w2^o#f=?G-z!Hq8C1H&wi?bINRGJ znJ^^R=7J(v?R$23hnIJ>vK}7`i%8UcyL4Cco&iT%*4R#+-ORWhi2abR4WQ27M%5(C z*yBk^N#kq_WI_qvWpXD>PU_F3Q5AWG{*tHWd&vM)-1^l3eBqdD2G}tYuAEwEY+f!KaC(#XO=hH7K^{TfZnwAC4?G-d!umuy#&`Ku_MD*k2pvxAQNv6yVnY zvgvvJ_t{gV(pb(sDU(X3PR-7VoQN0d0Tq5rgfE1QMvqBh_*^ZIgT}W&BLgc9MG# zGt1@ocdB~%xb%dAQfE}3>AUEDi%>tD5bKMMhO0~C(?%3*PAde+fIlw8Itf?iVAvyD}p3)0^Q z27daOT%4b~(uKhaE%YV#Hzw3-o}-+{xUGhyHg|Na+i$?x+t-OB0tT9VuR3aImXKb; zsNwf02>X(gOK{)T{o+N;`^aQYvy1yP7gX%+%d36CE*7l0p&!)8n~%ycl8&LFp^s>5 zi(i78?zsbwnmhOvd!4FAp6R1X(_wQ{$v%3BqJn~Y{LQ7MrQ~~EK)K65a|8EZOP*AY zXRq3i;Q=Jj9U&wLm8p4tpOaIUTIQWlB^leil(uh|pyhYkIa0%lescp!B_DBea`HLg ztNGq0o6~j5HNQL$rz|-xTxl{(0AN^^Kcd2kRJOB#w)-7b4r3A6gt`5fmM>ng(8L07 zKzUm1!<5C6G-seYHE2yaiWAJ|Yb+xz6r)ktM4lZWw z+uuOj#C3|&|e{DUciYF5=R>tgrGBgOW@RxOKwKq!$m0YPZ0t&6vj)aeEe z#V;BH2Bei29!yq~dgu4|v>c)KCT*sO@u7tbac^DggEX9iQC65_u~^bUa*LICrEWLe z$EM}VfJ-pzbcPj;9o$2%;f6aO)2a#H3tRO6~G>T)zstjYyct8%X7~`QdS|MMx`15<)}w^YDnPH>*K9nMhz83 z#q8dDryCVEt!-?2<=TED9V4@qbYondYrC@HL|0Ge&ny;R*biq1vyuq$^XoL!zjAjM z9Al^hzinfC1DES_=1Hsd38SG7zx{0DSA@6bCxZ=gpaVa}vQTa$+riHcH>diZH+ueCCA%>>^E^^KU#!ZY!M@DU3{>{k#1^>hz1rC4;E(*7E(b)< zr>$&q-{CazTp@pYI2hKSqp6gXm4;m32?`Qql)4B!P9psAWXP}(b}3iw=wmBigco6)a@BRdx0<$*Q<%O3~fRMv77UQSb&xjbv242^7x**3WmrumOkqUp>ngJ zprf5X}dz`($IHi8KQlHh|F1O||S{-uskn&d?2L{zJq z<>%$C%^Mr|*UTuOAPf-1;pMqFa7D5kiw3}zS>7LR)(lPGk*+&EtRtsfC@F`E)DOr_ zP3;agT6JmZy9DZh4Jv-?*rn?ahh8OWYaHCBE@{w`mJURAypIwbp2kvwGVx|J_v29TQ**047ihzL0Itx>6RJv)>sZ1Ja94r{cz7N zHYVnI@8MLfRSc^cyO0osy>>UUGeR}$Gd%j(wY9Z)+i`|7t06B1|n+=-KJFblB-lpfJEO$Mfit1syo= z-o0z?>|DJzV+P`SMCJ5g1+ z4sJ#`m^P15-CLittp+6E7^&ptanAAO*-oeU(d^yrrVUQ$g}H}$@3b6E_`5;NOhQ89 z>%@c}-^(BE54!2d$?xfv8(Ae^U;}dkhi+LYlRRg_q$$3e-aqw~ql(YNB}X9@a<26B z^lD&yPcSm;0MV1mrE+s~d!Q8-^_R))C$qQ%6EAO!5Ze9&`&l6^CO=u(YmxV;ZD;E3 zMnI>>?pC?{er$&E!w_YdJQ++Cj**tC0>#%0xSb@xL_$ImhAkBbbRgM{`{iWiZH(7< zPt4aIGSm6bp4BiifBQ;s!6&8_^PO3K!g4vvVMF*^;j0?t=%>NwWCRsO=$<10*x?J5GnzX2A>4NpvcDzYcB67@#1|7pDi{ zCXP%HTsZG7D+;@B8%=?X=s$`CND%Y*%MgrKNzKbSt~YbUgwh_C8NL=tXhn^U`p}E+ zL$z=osL|*IXJljy3=I`iP8&g+O3OA~^P11*M;MRvSFh8<^7~f%GQK)@6{IJ%3 zZu-Y$QDNbqcyNnSp~VlV&qzQk#IX18pWVbZTux5!f9`Y)thX%%52N$TSD33g7!7h> zO&59-sFL*e=!g>h^{-2gSoHMt5KiBq^c5-^J^k##bFn#9BMr_$c4np&c!*)}*x#n6 z(mDZSoN3qr@113JAW7!KYosYNYW-^?d7N`M07SCw=bExXha>A}>`76l6o?*%iSB&X zn)N%|Le4m}k++@iMH~Z6e1m>B8|Tv|Mo61Z3_>vms0c<)TPP?`_t{fiIZ1*w4P{7j zp{_x>Wlq1-+;PARgn8a%LzFQxGAd+>B=cF_sR0{z&O|{)B^C(8N7ZD$q7fNft$dZJ zM;~aHE-}>&;ov~ICK3%*_@kwdfY0v%F)JHuJv}@7*LpoO82GTfq)|dR*LfVM({ekF ziKat_LJYJi zrtRm0^6;e)b*Of{9axR;;yD>1xTo5M!6oka-~tky3@fu9yyY*Xsse(h?FdhJ5at-G zu%mXzJpRxrAj6Wvg*bngEihX8gco|8kMn|-vt&Y5T+Rm=5bsgu+U{hDxV-?)fpmJl zYD#i3N1`->TEuxdY;&xHGN<&qDv0FDFWj7*-(&3_1|s;}{w_)bed-OfK?A-M4>U4_ z;I)NcWQej#00B6O%%ZQ>zhT)v1R?Yh2qdr1BC12YHWN;DEi(q}e>kJj8D@*l!^5)& z!IV$6353J$t=sb(Xn#5BxW)uTN>WTD4Oo{4P2I8GYHkBADX$-tv6A43oTn= zaAQzsK4$PAx~(x=5UnoBlP-oss|gSOdxz%)t%K36g0{9cEF2sXP^a0z z=a5;Uw@9|(01){MD=X^*cJ={*?i!m3PLz$&1?ENRGEl{8R2EZEgtJ|FL)UMP98lg82NlaCPYpdG#hTa;U-|B$9`xCvgX|O^pp^Fu9(XC=D)*3_Rl);A`2R zKO3EcS&D??1xPr;LHrQwzY{1Key57FzDILNF8`B=MrhUjSLfakA1i(|d)p1R%^BRKR71|Gml6GBMDhPF%GK0G6SAnKC zvc@_1&`b$|ZPk`Va={@U?jS?}HTS=S#YAat7li3YFsjE6yL(XImI=l?XO#p6FBYQk zMoGmFr9cEC?elII4W|}E*CL*Ogmn^}m+un?J2;G_qjOT#4oHy^?+ z{^wp}{EmxK39Llkhnrb&f8H?3{+=GxOnAde_-!ZE0r)$If5Ge;m7shliX#vSiIb&W7BK{y72JLtH^ygyz8=0Npr%%I*@(FuXDAo7RN<|*h-xJx)vafFiRKepa7 zr&n(6LY5ErBHHng)=!&UmqthsKSQ4GNdKroeWVs15n-pn(D)nC&h7RYQ$t((MZ~X6 zAq4kNU`BHx1a#IZzfKNk99Rkd`vS?UbKXugM546O)^_twJ};V-jjn(A8ib=*)is1y z<(`(x{w_HxbN*n+_8(z))UqHOj=vh8A#Nw-FP#8Y>=Zsnbw; z6kr8+6HiFAG&G3+yTSP?6cnIzu<8Y%PXS*MsPXZssVe`iwJnL?h9VdZ9!DGa{bn(65yt?Mic{poz{=zwGIo$ocfjR<`J)HmN444;XvOq*rJ`67iXQo zW;@|Xf*inm#g#vhgvmUH zSJ$btbTN6#v>Re?olqQmOJ-Jhzmp zlPpNTY4Z4Sv6M*^x$Z1n1+%!FQ{3I?mZQM=Q zYs02Ym|l``!^C2(@9+6hb5Q$Epg83VXOYsske2JYT6uWDa5Um08}Y3h@v)8gfJS_q zMts{we0zAkp7*Z>j9y#MpXlKMBSCrL4~%cbd!N7eo;aj`{#V8ZZa^YZ6E$Hqx1 z9?bRN02?(u^&9x6UG4IwJ#B3EjE&7dwXtQY2lG8R)PtTjwEoJ@2U?xaSpLk;cY4ak zu=hQ<(Sti}jM{2r!e$%OF10b+bDf^rzx?%#@Svw1z5ZzD`yaM($QT<(EVuEpaUQ(U zgLivyo{g8gZTyYrey^&r^JAPgj`g&2tf!r0J;#eY{aX}j*DFe}as0zJPF&`}N)LYG z!5tnvYU3o&vz!#{$vbQ`3}>JrjmU5YxWwhED$CCkSM7^eROgBNt&ndcam>YrZeZx_%`4OGxS->?7s}sc^?shQIVO znn|wFQnHNz$uinXh7l-fMzEw9p^{{DlrBbRNif32VMtko#2HZ%W5h_b5i5~~Ln4fL zakgG3N8LMDFPV4O^;Zte&U84!{40;eI1;k+hK{-M-p5~AcPK*Y554#3eZ3JO z;)pQBkt9JzcWGhdOB2J{w4XTJ7~)R6`Qt)yMVG8L`-(g1!M)t}uyPl?W6se+F-vxk zjM+po@(YsDUy|H>n8T%Wsbprpt4H?1EnWzBVRfO%!suV>nHh_H7>m7(79v%-Mr+A2 z+DLb!y>v5zB;5#+RHK6=Ga{21kzE*(3EH>i4n|}gBQk~&8U6h^;LJI}Z{|8t?MRx?5Rb;Ls7 z9whN&nE6Y-(Zr(OtQ&e6Qm$z;$upW;)RRG|q!Xi352F>sQ5>4;z-(LSaKcXmKmM-SNXWEMVHC5c5XMWjE*882q9jUC0@6AL%b4Og4z5HtJp zPBd%;+^zMUMed0cGwSUykqVgZ+iCgsqFCmoTDaP*Sdl;QMos}=rL~9;U{g8K7* ztOtuht#B^~i;luP2orW3<^hfz0&fKMawEXkIT-08Gb@nSJfX_h`@Y`))sB55Q92u4 zq@y7RyGjQmSwf8z2{BSxsz`B~1R5FA-smRnj7({3VLD}L98HyAtET=UiC=c*97o^>;shqFBMa(Cuvou{*zv&EsQJ%hKh=JXz(`8|+U zJN<&?c*=#>-7~-ZopoEc?(#o)eEZffK74)g+&jngjgFOu>~VA6`X)^3>$kkJ#I^6$nSI)cD|_Z@cN(fj#mtlz;=X9{p&W5e*9 z8d6yG-+Qen@gJBe;XK_$q-rS7rVag`gIpCyZ)9#?1TlSJ6bgc4%Jn7_cdZio3KLd@mWG&=!(#@vz)H_Q!pbO;i!G?H4^!@LtEa(@iBbqHoj zjL2ot+z+@2Tn26fS3*PJUn&%N7J2}>mb-KfCpnry9lk zD_7Ec3lL{ZX7t5OEv4Twom|7T@)ntt1~T(u7Vn3dPU%*#2;2l-1#SSZ^pxKKs$yKm z4aEwGF% zYG|>wUnx`lx3^_>QPYd9{pNYJ-=3b;k!rx=P#xGN?;6UxvQqR83PtZwQS`3J8X0EQ zNNY4Q!l*%p*F(PHF)o6TZxV%urV{XZ=z1uVd@cAf^b~XhGyqcL3#$fM3%vyW9@1fP z5!3^UyHkWUgzSMnh4lAoTzLmt3B3xv2)zvb4XS`t&aQ#hLEE5XPGgoxI9xiUR~-w@ zf}Vj^LE9l015w4U3RP7+_3XPT>kM8BJq&#a)l*gomO`|~bVp%t_1*lh^~qbxj4CuX zdFSNDsB`t1lx)brP^_V95&dCO8~(paKXz{K@iSZJ%{RUa<-K?5MU^^Od$+acHRzfu zlE*UiWnPBggMGnjOj;YkUgU2C@1{cVAFjOj-wjtroyh@1!LqnHUX61u*}0!*E#GhErvT zxitwR;SqXcO%yHvfR0{@GPNKDOEeb3V$>(sR4jyPC{HyPp>iKUOWKpu5n~xj(#Duh zXcy>6Z&zah%s~%&79-!cXgH=b63HLUBN-EgaXU&iA#&9x(TR3;i=}_joYqIOa2ZWU zuB4M|In@&^m|noro9yC5`GTYSdE)PX4I{t}b$aI;lIzb_F%V@#A&)*lr%xc2xK2hEcSg$9)rQ zX-|4}m4PZ>rC8genwM%}s*TA(ZRKfic|0vw!>Afa)mR!M&Sw2^@)Dm=lV7rEqbXuZ zCM1iM4e&@6B#@P7(mXz#`F91js-r`gP8VX*+NpLfrx~I%Efe|JI%f8jn8^klVyb@v zUs1~THagiN4?2I`8tHIlcg#>N32o?u5P76ImZmPqmlAgqVjK$cq~Vg|%+L8^_C%dC z9jdJ@o`fT4dV#p(+?OIdt_h+YxtQNdp9>UMgX~M_D(-ReNT4+AMZH^`D6W2WayKG- z6H>5})~6g|!A}0~O|YinOA6c0fiV=khIGTHBp-5M82LpAxoZ)?uTb8b{G4WZQO`%X zJi>t_3htu4N4p_^ev1@j;Ve^IARD7_;#}^gipkB7LN0Eghk6{R$`J~NARt%JQ;u(S zsX;+5g7S}{wEuIeuB9LWfq4r8@EvMakY5}?k6jJ3gqnXvM7k+Bkxz$~QFA^82k6uN zUD~q7K*Zil!Irj&*(j7F7CWE?2jsq)cvP!Jay@z zA354v&c5yvVB`p!rWnb|l>xXd@MG7^}U1ea>^h1sH z=ag=O@`AZgBDr9G91kBX%`jay1)Cc&@WIjovt@G&BjJO&TsRagt?&WL!4@cttub7- z1OpJVt-v-`SqRM!qKqlKm?)~U_LPTG)(#5ATiFH*#d8^8VIX#^_T+=GY6XJ9h}{oW>rt*6r%Fax#)Y$ zGtM4_S0JXw*K>h6t&nI(yNk?Z^rcs4iTnl`7rr(VDcV+Kc{h||q}hCK_gJ8=B3K`+ zL2O-Ki*oryFpl-T43BB7PU1InAN^J8u4cjFu4KXV=R`|Vi<70yZ1L1!F% zl;;zN7TN7<76V_PSVpXmCb)#m3Kjzwpjs|u4RC^`gwv!8UqL$^iw93ep|1`&#Hmkk zjg;-EvM-|3cK(0|1>Q=guOr)Yd> z2lPt~-cyH%*EMo3l!NL(`99?#puB;F8dRtOh3ZJrbE@OS>mkX(HIRz5*P*W|SCQ5inhw1H?V`*9 zs;lL3Xp1L5jW8wO{r*=!U#~mS4ypBesqHt%4z2Ziu=P#ydbPicr@bv+Kg7Qu&(#(? zjO}!rz4vhD{dw=(`6Kb{EX4Hfc@EmoyL&$P6m$q)ZOx0IWAKx}kHAduQRoQ#46qs; z1+E1Lfm%m@r+J+xHh@#G3mqsWGY6(273NJ!$B@|{Mdo=jyy)hxA~G+N(QDN>o39dI z+y2FVJ2jG}%sW05(bX*5r@jT=I1NQ_tcEursA6 zh?VPmvK5*InZ5Xq685S>VUl}*<$ci>jAj)m5GRu&Q6QMa2Vo0a#TtJpO4NJs<5}j< zp>_eMJ{*S|X)*?~w>j_umc8LFuAHaFzk6s)b`7HQIqJF3qd0aCX49zSWOtTwf$C5B zt&`s_=Vb42(yj3Kqrxmg@91xmQH$Q)wBlKQTtAprUS$&6SNaXvqdDBqdG*m^UO-KA zZz|Tvw8Pxz0u-EmSxvEQR-?jfB6qkqCe1bIC0Qpzq@iXYN($P}1R@h_2S3&o-H0~2 z=qh3n%4PfOrxNZ+4|J*g_vqpMIZ0v;tK>G14M-Mu)}jWww`LGuA;jLh zOP}KKG;t4KR^N_uPT;Ml<29O7rv|f$y9MT;oU-D_6k=@tuPo3SJPZn!kln*g)HmkH7}n z1}kJ3Hqf@@J7WWFOTHsE&~{)44~Am-Y)@Y8p@Co^*3du#N!wxh3gSaDZHD)gN>wrA zEfrJMOgr%PbhxTi*&(c5EvIH@E37pcld=ZEYWIXe9g@i>{qn`oQA%cRT$*mHNGNQYXIY$`$v4C(myxu7dF|9Lf~; z7xM-Oh^tTOyT_BnwX6L4c%De^4U5;+5hHbQ)g#wnrmai;&8-XG*o+OCO#( z1W)vl@QnWFj~qF+_^OeY49rg|aQd+v@jX}HbM?KiznJ$`r9~*ScN1o7MSm!i8QqV( zN)xfr8w6_Oj|ZE2KS=m4swDbh;(M|xHG`_WYD{Vt{XQij6PecdO%sf+QjG5D$V6@? zQ#Xd-*+lM*ukrk@lxX5%kR9LPy3z=Y`@xs8F#-$xNhh zIigBG*xpR-1>kI&GL&h1Iw!oqO~Fb$W9|`zm!uNRVm72Pjn?+U30KO;Z}Kpz>AnP_ zRNf`CJzC67i(4WdIOpIP6zCQVHTXZF7cOar-4%^(Cn}cQ(?rZ`RfTmAz$|bG_lv79dJp@ylOsY8Ogs%}gZRdYI+WFe}kezZ`*lTtvHToCww5^F?6Yqn+XI z=QF|jMe*F!oj9sbER09A}=NX#&cYl4&xLJw_<9;rHMGgbmY$kpa(p21)XNOe}# zT|>ZDmQEW2O1Wyip=hxI);b~pH)sgIZi5jygtN6pTMY%@M-7( zyndIaPShjt>S%cvdFn99sK0YJcm=oyRIlo59PH{Q^E6CC1B~uRl%gf&FxmP$-E`TU;}6vpWl-+;zYxYyajUrrw1P_gWd)!W@{M^HX4k*x^|?p#+W?$jqwVt0)$$L>08 zU#hRc|MnhMA70~6BUx7#e}9__d#eiXHbXh5KDx9wBFg1uv3)h(I0SFRfqurRWczCD zIC%ZwQwjIEE_PcqVPN*K+Mu2z^*yp|EKmLZu34vd$g)1pbe`dLWF7bQ5XMb;0VC*O zG29BZ;n&ZF+h0PmZYar`VI=SMC8-)s@)ZZ%`yWcuJU?+CS};Hh7E#N!>&eTjIYC3E zGhmhcqR-AmV1K1817oZS%Kk1}!~9fjQKd%}CH)#sz0!PBP}a`+p4#4C3RR`7x%DJ1 z4_m-0!`Z|XSK_qWb9;)ba@eC^Ho+pcdhWvnHgRk5;8oi4J-hmtiq?hA1;j8xX?gT`bOfZ)9=qo(NawQuPYI*yUfNVmyfUk-QQ$ zbmgD+ttNZ7A0o!9+H|;2IaKfs4nxUP_h&GlGRDvadT@>05*3N_s~~d zC?WGvIU;6mL(#aJPa~?wz2Qc`=-y5@^{Y!`uI8(O*H2`K6;i|GD`p{upzhA0(%>=Z zbIQ~$uio_VF>i}<>$Q74_A7k%Azx-WhLcdqWzSKqt$s@HY+Q{0AjWU6f}+kC%?(%w>?lib2wKv=j_h8v$#ek*ZRIoQa8bC?3Q!}uz)`6JaDf0;f(UP z$**M!h}7>chLd?Ijm@KfK_{iDeJw@8yK{_p&lpug&KA_{-33Nvg{m5M*qW5tftVVA z>HHBD<4l#~$MUT1&KSMcc>j6Ie)v@OH74_1S)G}y6WE{mqUM!%ufKmpw$OLrl+HLi2-hozdAx|bU7gQeeYd-o*KVW}~= z-bhM~p!7yf>Xt{kV9~{jvt>VOnz41f$7<2Z;F*5{&Vu^Go8T_!AJChST7YzY{~4qK z?#ZBjuk{Lsn(C7j+(c#vcryjzY7?q}WXuX*w$IiyAsyfPCw^R6HRjl s$!*`C-I~r4=V@XC_@6g_r&#~=e?nLdedzfw5%j-unCRg%!S2fcABXx#lmGw# literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md index 9cada9688b..a28f1e80ef 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,4 @@ +![logo](assets/images/icon.png) # Benchmark * [Assembly Tests](AssemblyTests.md) From 05ed7ba2a2114e4aa8ab13df9b7dde7f73665deb Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:21:47 +0100 Subject: [PATCH 135/561] update logo path --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f9c3e45e5..dd84c48c14 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![logo](assets/images/icon.png) +![logo](docs/assets/images/icon.png) # Benchmark [![build-and-test](https://github.com/google/benchmark/workflows/build-and-test/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Abuild-and-test) From 83939d0bd447eaf958f2dc26aad8d08899d9dd0d Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:24:38 +0100 Subject: [PATCH 136/561] remove icon from main README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index dd84c48c14..a5e5d392d8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -![logo](docs/assets/images/icon.png) # Benchmark [![build-and-test](https://github.com/google/benchmark/workflows/build-and-test/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Abuild-and-test) From 87169dd3f53e31d82dd78a3a8e118cee30feaba9 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:25:30 +0100 Subject: [PATCH 137/561] remove logo from generated docs --- docs/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index a28f1e80ef..9cada9688b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,3 @@ -![logo](assets/images/icon.png) # Benchmark * [Assembly Tests](AssemblyTests.md) From 9ba2af8d5297cb94d3f9f8f2417b27b6957d8da9 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 21 Aug 2023 14:29:46 +0100 Subject: [PATCH 138/561] add black icon --- docs/assets/images/icon_black.png | Bin 0 -> 11559 bytes docs/assets/images/icon_black.xcf | Bin 0 -> 36322 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/assets/images/icon_black.png create mode 100644 docs/assets/images/icon_black.xcf diff --git a/docs/assets/images/icon_black.png b/docs/assets/images/icon_black.png new file mode 100644 index 0000000000000000000000000000000000000000..656ae797cf4652de02de79fb5c24b37c94860609 GIT binary patch literal 11559 zcmcI~Wmr{P)b&9S5NSoaTN>$JSLhXYh$dM+IllA7W{O z{{-1cNvSDFNl`gM9V~6$SwJ96F}^XP^6f9lI*l|sY1pteab3IB(sz~#BdaiE3UF;d zX_70m-v%;ZDTIgTEb2NQn3ZoWE*BMkETlsB3#hFZV6K-By;s6uGZhiogEe?ZHMj>1 zF}>*D3PVaYtIhEQXg=~^aoF)Ao{M3#DATzC<#>CCU+kx}znakVny z!;(!jL-|9j_zF?ieU~{|dY>N(9@Z)l()q2{FCUSv2ev;L#7x^96LCt`W_2kW`CVjf z+o92c_jZ)osJpfZI=@_$U{~a-de>(B%1Gz0P(L1BSqQy6?zgO9{N4f@#llx%pPuf* zL~o=bjcAf2OYn&VpQ(L7oj&|{|9k&^@y%*b+S4z{a~##TTo@-i5Blrv{V8YNj!_Q8 zk+r;Ljcg#lGQUsG>aL=1%%ZZF%%)bL>F+^4ss_L7japs2~c`5^p?acIP}jp2=ji z9(p-b(or`q$p=ISNks;QP(kZksj{R|<#e9@Cf8xWh?H6T-8LJV`fN`_j#D8_gP4GHqBv_|4lpB`edF8sS}*7CS3lJ*XwnpMa84zV+&i`pJZY_wJvq~>gY>cctk`@ut;(i4GoR8Nh5!@A6O8PnP4o^ z)v+HM7PHm%qR)x-IlRtxm@_?=A9*geBH=%T3`Qp;&|CE-Q%gxnDWIr?Y;0Jk#KzJb zA05d*g?v5l-uU*JBG$yj#O0zmWWLE8u4U*clOg6Sl&Sl$wOX@Cn;H$9OdeL^d~tc% z^Zh$rN=(de>jwd%WP(s>v6CSwZUKShNPUTp&d#1(rKDIoh_;5IVa8W(i?EZkv%FD0 zYDp<63q{4SqM{o zm^JdcbL67H%?dnyT(*mAMv!Lde0+V^z7W4yty%C>iiKpglr~=}Mw0M`VNZ5NrDcHk z#Ychoj*XA!=6(NukUdQe*55)`mqg*gOL)^!FN?Civ-Ka3m58HXgJQG_5bJud5WRl4 zSHq!RFO^fcWhN#jEY-G=^hX;#k3E7`O@>PhgzHQ@F=X)|e(%B5R)8>aNu(fi|Ks$z zsGxvK0dnEb%*^Z(*@5$-m{12t)7aEAF zp-fiG8axSJ=e!=a-+VnlJHXG$sn*fe_5XsChL-lz?Cvu>JUkj28p)u~pTmcS)To1S zk&uvRI5`ih!|%_)MiC@r*T+SCz~=dPBNY_juC1+QH#X|O(b5WkOvvsbopQD_tzm9y z85R_TGQ%W~{fg81uX3I3_;a}oy_YWoHYQ6mHx^o25FdGYdECRp!)%TGSG`-W6%;~m z;6`^e7>^&zn3#OKKpZP7DSe6`@FsaeM#idHtV^HwDqT_d;m*(IX0d4-mIAkpA&FNR zB0B6k71DdtzhD(j4)*r;U3n^Lt6=t5L-1(L!H{MpAK+`T;m_EXMNy39a&vPl-1p}r zJ*b5o7heiG%!{NXC0T7_Gcz*E4W#j_p6$*~;wdaow%qYPdQcWOD1NUGhWTBc9@)~; z(s(=|ytXx7Xklh%_Vr2Wa15>7YPL+cxv6P(@skewnmO4($PN_?ixMg->I`(fqTCGD z>pt%ZD}S_P8x|hEc04G~(cr%S9*%<8+;+CM^7sL7o9^$fMr|Nuv^^Nhg+c4Jo?hDFh!RIncenhk{^}?iD#o8X6LY z@5R#R5f}^>OD>tjZeZ@^B}5)5`S=-Y*$(Cog{W8e6UJ9+l#ra=sq*&NYfc1GJbe6Y z=uz_b@84IKgLsq%J}zP)pb1?Vts9htuANnTciDZLEOiav8L(>LzH6JT@J%-bY z&dbZo&A`y5jwL1_pv|sV{YBP+3rwzUvXJY~HT(_`%s*HH=7TYbO@9Q7fjIEII4~h; z=#<0LB(-7JuZcWj182EkB`^3Ob38Nw?#0dkBo|0*1`S`0Mm1$6?>Rtg0>2oiR?DM?9l9UWp<+}eWdY{}rDpyUZA@3S2R z(*Rt_ke!`(8c%}G2nZn5LA4-SReWKst9&JK;UH`~p;`uM&^F9R&jheAlyTM*R4&A#3mB*xm>MBbc>seb1T3n^|Z+`d;XTMQzT zA92L272A(bPZKhIjvhteOr9RJW5+-kO=2!BnJVtMWXy)S&nTSVK}8iGUHvtw&u1Af-OWz_2#9uCmJT z?25->x>zNNwCc()oEaetV3&;`$!)~GznW~x!)~w3@W1n1i?F@9IOKW0v2}5{!Yv}A zf7zu0_R*MyfGPrAwou2x6zFJZNPP_4nI!J+bq;%^d#PHHlQ`@ z2bxLC$+6hK+;2Lkh(PNtFofQf!zgn6+V9?Q^oV+$Sd(DKKWAf000}_R{fphZcVBW= zP3%BmstK)%c^pvnAoccViW_aJMDwLQEz37(aAUUT?CI&@AxdW8=2q7+*dNJ#>`H#- zdVhP)V#oUJ+qXWOfFJX|=LWg_Qfd4SdCl#9B&4J(fq{YXyz!qN6OO1E*LQSCTe#jO zwcOCVQk=ylCgv5zSTCd^=fV5>-e~Uo`uLc;y7IbG{*f?XGxS^|AVFs}J6QbPyLAU3 zxZt`h3W3!+D?^449we5#ZfjbcinFsvUg2EJD=5645U8A<49NWhc4Y5NfZGdHZKL&p z^b|~#s66P=`bw1eD`>#!?w`6iStN8GTmm{j4#|8i`+6mVHId zvaR7Kd9Xvn&#yI&rSbYT-fr8H&yLsP^z^i%pVdT>&T`#)hTZAHkAi~es;a6n0sY}D ziI4ilx1=@mUWJ9KnPL^SwNqTXIM#`AjH-$p931WYk^1aOfYpw!VQ&VLzE^85cTo3p&?k4Shw5wLx9c*x~bTf`JNRbu}=Ctj~R8h#EYg&&2_FK!EzM8-{4C1~Ui%H66h?z3>9G zrp}lS?f6HnQfNpBE?|)FPp^Zc#P5=4K0O;X+od7sS)#nZ_&l_7tQSqjDh?&$dzVb1 zpscB>sopST3RHu`=>ie|`>${q?4pX-vvO6rS~uaX3_Y2MM_G4oukH8(;8u=6@AL!) zK5*h{zBy8I+WRADOI89@hH?iC7XASl?G8b{itieHuTHoc=c38vvGZ)Lt%+s_-2wLKzqm8E) z7)+wkzbK>p+&)&FVIWKee+5~N9!n5p;@qP~c_O+84UC_|!Z6sydVY&Me{SsK(@1aW z6U!-&;--kbKA1^3K0aRIygtBgi`pY0NFX(tA?mH`CJ4bt4b7qlNz4Gi(b3K2aW&=i z$5mt9weZl;^6^euFlwr9DGsIByX!RmXtI)x)t)#yG;mRCc8`S2HA>G?*w)sTJT@IB z{s)UCpqZQ&9bS(EjMn~h;`Chw~%<+QIAn_x=+swQR zwS$~C-(A_Yv$(%`^E9F15h9b<^*j0a_^gHzu+;i##iXU#UGRdfl7I7U9;^sv=^rq= z`A{P%pjefal`D7lY}k{O*tN?7?5s!n-=6QyF?$!(fN*JNIWIG5FZiS7bg(EfovTEs z_pbbsbvd2-70gDwvd(EG5N68R_vwnF984dynD^Rd+gw>O3&(3;8wR^j$Ix(q z_crF+8u_zlvN}>tfF%;or&t>;zRVGAsd07L8dI>{FEn=4K|?`N8&GoqBsJKb&V9j` zKS9qKx7L#J+7oE# z={w^}%fDI70yP}VF$VAH;c8qV5_T(sY3?DU8sPWBLf|PH_Uhp)CC&y020w?_w%i&N zu+>yMF$V#o_cC8IZ1KD8ObVrVQu7BIF5vd;3^-EYZ(#ytv?|oTz~B@ z29V>dV7M(I8>CGr$U>1Vd)Mdt{Ee&*wM(e7*lMLkMSTaoR4y;Kc3Hf z4<2xT1uC!y>95-1$eUUIwis-3A-bHL9Q)&LMm|1G4C;~Qm8xJTcJI28-jM={7}?P3&~jV-mB%Jl!27HycES7Za=ml6W?_D- z<#^QI1W>H{W*|KjBgKV<_2}s6x&chU=t3(hxZC}uIyJwy5=0Qc=sNgzNO^aFCO60X z(@0=(IF%r&0&{VGuWU7Vu}YlK`60+u>op zjV7t<8Qud27=G*N?laASK&mm?r8Tk42`}ZRZHt^unbqIS0W0Qa$E!%M=2g8uyT$t7 z-Cec?j}@$j$;a*R9u0=4ZGrQi>*Ne=1~8!I%=hP;5*UKJySp>(e;&6Y<7^z&@H@== zbZ#F41z%xp^aLa=)t>y;6E)5VzPJQMzlc{^AgC0D`?9jAE;|X0Zi@P1V`E(|uQxY0 zwVEhE5-dAHaT*jopDOWdJe|-hDnzjw-Ft-<1wwwNB-;w)D{y5ld2UTj&7WGQ6#}>| z5Rvsa!DqgAZzD+gUwH-+3At?0bMzMP4a-sTHY!(cVA28J_K*G;+@d0{<0vK)z7TIiq-;_=^hI6JTmw<7{ z!zN*UZLS?$T~Yka30P9GWX4$OLayA6ZFW)itSi7bOz`vb%X9Gn{~nF1irYgyS65dz z>NWI~dba@w;b)ToGq1bM1qa4Y!q?L3byQ<9g6(T>Pfs076WPr@Xs1zkBdr57zA5MD%VIb zadwA;Y$`cimBV#@SypY_0H>&6+X+b9$_pVfVK?Q=SQ>FGF!u;IOk*o1jQH5iC>#^} zd-k#&hkruh&!4fDeOCl*H$f-R`@8-7lI?PRo87#>Q!V~2N4YXVJ(=~k@Khp-nMT@H zp*L&_zEy7}BB1}JKaD3+c8o~2q<7l3nE|KUlW7$lA)Gc*7H_>ht&f=?+a61w2+7>7 z;?vXFfPPipZOzWk25Q-&aNrW?jocF0Nxt~4LXusU>4UXX)4pV`q#bXQcwmCjuaBn6 z`2|p8lL=()83&F?WjzhSmYHaXW^Hn@o`3K|-`sEE~Ia2Jpr z^->v}QbG{5^n$Ial~%)w3>`Mx4>$8lO4wb2>`j!%R29FiELqPx&mf)A$1zA3aB8dM z{n=qb%CLDkwX>FFqzU~4xD_3$wiY5G{#-w~KQ+3~)iV?DxhUJ2Z)%{&m(ob;c+X%E z^?DZi#@&+b*w^z96wX$kp7~S3e+EUkwf>F$6Ji1aaLo|kPkzxa+MFtS8uI7%f)PK( z0q^alXxC>0qB<9T3EUm2X|7V;s<2gvo%i)_O#*KS$W*FHs7@fM`25<}_CDD#=@#pr znS50rT)kFcQW-fApDf~8@qXP6WPB#Qkm26zbO`Y65fbuEv1V#?be5hJ-*MVC0zy+eKSV;)~MwX^1NC9S3!+wCw}(?!&V*uwY?-=z~sx*YoDrf&L7FG z1^ngvgeR%xT5p0Zc?&*BDC$r)Q&UqH;e5arew-7U2A0MzKK+^a7+0wI$=MgIE*l4@%a$NFClxr~xl5+fK^!u#*r= zZ~$=8=k`N@x7ARum%pDAS|cA#WYhZ&l1B;01aMD_XFUi(+81J3YFBaQ~xPNeDsGZQ&^BNHCBnzeK9=d5z>@6KDaQi&?rJdv(7 zs{HplhcbR`|I9V|w$a4(>M@ae*9@v?-p}IVegN)rzhoV~{I38(W}mIJ$*J@!oR=f# z{Bow!IO1_W=kDt8a)v=lCGvW&VQ@^gsHv>7^G|Hzb9VN`-I*$ldNnhuhx2vf3~=&Y88bw$cYf7VmL|T7 zM^$oecRJf&D0P{mF&RQ-%2&-CXqnIGn}I8g0{TU)Sq|b zRGk-mhK}V(kx*D=h`HO~VK5Gg7nnqxi$BvXWn@0llNm&@J1>SZ>OYt}ujLmgTD%9gnib%9=RZ3*#s?=v;VPTs#K~NE~%hkAGve~=a z>)fCHMSdi}+@(Vk&;yzNTlkCt+Z{lr@v<&nzZ;LstL;*~l0&iElhNSBAJq?kzzV=> zaN4SWD;x6C53sQu%&_lu`|8kin)vEmCPzG*V2R)vJL{QOC)kU=#gqs*c!B^>IY zlhf02SAtiCqZ12UtbFgL7P%~J#+r#H!vX##bwCEQcLVc8K+0e}=8YNtlA*WEObZ;Q z3FiA~07A&f$QGWSf;~tX>t4qXgV2;0xns|YX3FGMR9t-o|Ni~^d~RBWs5XSom~^JO zDX$~w(G#+TgD>-YZ@kBrwfl8arS^wP$QSD zdMYVzFBXvV6|k~}4d@F~8y6Pqt>rM;AP`)gPiN{yBAtK(-VSHw;u?19 zSvsPBjk3*%^cRes2#P{^e9DYX#&ZqsrMqW4d>T?x?NdN|BY-z!7dyIYlF_jFjPw0{q4 zi?DuITvVidwlxkPyZXDfM(@5e^}7J6mcpJzT0<($;GG^2SBkv~vteV2AiOz*-FB?K z3|`ni)M<4BWlfc|gsaio!!A+_grX%asbN zPC4wIbFreLqPdOD4<-%{LPS-&)c>|nz8;IK*K`;oxuZzvx>Bav;0fIuD-A$kES`aK7exui-An`XFSzy#t53k$Pe z2{1$iRc|oMWSG(ImR8Y6vn5hQ1yN}{36S|-knv=(0_LBw>6-uOVh@U5T3Uj3h7s_1 zJWkvXSI>VP)jS2LVRevhIIA9MjcfQlp(;gPBl6U~DabjX()s2P{5)#}m zUc_}kraFO3&RX+K!#M}wG4yX=3iS5sw4%J6Yv9r38pvSK=?V)ds7N46krR{oKyE@8 zntka|Ti+vAJ#<(0)a!)Dv;+MTRHC{E#jgAK$kkn4tNOaTqY-5&`({2{#gn}`y~M=C zSRzP6Z-0N)m>;eeLpV?ya2SQRGKeN!zteFoKxl#WX6C;4hxz^jCf>U_nh&3v(uO58 z;7UePi0bkoO5Uy#yc1rNI=~!m1UXYiLgGWt;3&|5CtKr6C)<;%pidwa(OE%C$^!US z2NwUIETtwPP#^Mp`*yq)*p9C?H5qz)dpm$kVFA%A4FFMj6M6}TjBM;&l{$-`=2@GQk9WGj0DY1*ij}>5uNs*G))|Y~yl6na^toCv_ zjj=aqps0P{PK!<*)QA|wr5>owI8dU90p>NE*aT=o;97VvB&Dc`K~Ci~o<93#=Rgaj zI1#G>G6VM#K#dX+sq|46FNlcT+1)%TI=>La;(&^AyYM8Ctv$dSBB~!U14VSyVlwM* zE3hc|qbCeQTwWd**Vk}DLl21_@^jGmP-q@&3Fg2;LINoV9o&zb+Z-4~n@pmdfC4at zhlRzvWdE}4SND1kDnCbYs$$d3f&CAPszAXUmVmDJ@ef+nd z4n3=?+F@aUPz5{6d#_H8LflVZ=ksMROKGxKGs5@<;)zBA;w7)76o+Ut$-@p4^S$Z@ z702B4RYD^llh9A7#1asppFpUpC@2h{I!m>ET^s73iOvVz6p74evbX^Q%~xA2f}qeT zq?;xKEZtRLCaY{?R=JZTV&J0~2Y{V{=uHtaB=t#6{rZ&^ROpp=QHq74g5{J0B!GOO z2V6o^$n^0%f%w%%&QV9`lRS4Hcp}>`A04hh2xcs(+JhDuli6bSbbRoT-1PJ^ns49g zSK~6|a?2V6qN=!zkY*ow&09eI)*oRFnlB|5(IvfwhxD3=C$LN(3 zyFnMts3+-D(2fLM?g)h<*wXIMJaCm}n{rH0keGZ{N`rjYQ5F8_GZqf;ErqCbP$RNX zSI6flFU3b71~YTd#5F$X1DUP90dvYw2zUSjSI+-9N4=Y^E`~Y4E;n+bdco}kvo$KN z(PO}KQ`gniLGNxZfhPZ*s2vXLM#sTPQczGhs+u&6TkyLsej-dgYeWkMlmV2qr?Qeq z(4zP0?7lW3$V2(cDKw)aBj$d7%`3uWpuh#|nwz=^!uy4)5%|M+6%nNxEP+hXQ+c%axz?KRf{K4Y*ufTr_-q zXP-ktL-B@(hsR6~?~Pb|FV~VH1u6ag{mX&icLLrZ)K>x9F&6YNbYES0y*4u9xI6d1 z*V3ngXq8sSpqI0Xlwd}D+%<6kuo|?-P~RcQ%_zBpM9!+ zgIjUVKqwvxq;h1tv}JE<{Jkd{5`@hK@HCj8O_!E3WC(+Q-XkaH9BzyP{!j*zgxug; z5Eu|P^Ycq)5NfRu(Deen8DRv+Sr0)6+8Um>+lxR*fMs`o|7i$;hXO8SNSUMQBv!7d z1WwBUvCfmD@a&+)4+6a|e<~~qL-_z*msF^ZFo%jSs81nA^~b|M9!I4LNn@`Mf}LwG*tim>&?#X5 zJ0>t%NdFxaW<6WY7K#LBJgKYYcD5yk4AP3J>D#fo zzRn1g)PG;{SPo^B$3#3N3=ljTu75^mY+74gjV6Nx;B`cmTMyHK0i&t>zD)nJiX(!w z_EG?^Avctop8it@1mbo8dW#f5q_&Ie_=41}fC({X1Xb_~VATiH1%r&!b93VZ?l3jJ z+!+pX$^<>L%g)s6yxiQFr;t`=AkG;a>NoQ&8Bvnp^q(<_X%>Lx8l{54{u2k1&%(?c zlj(Q$W2(u!24OT6fOayFRS|ueZ7`S|5aEdQ?sdM$CL2k{-1UW+7J%g@CDQ+C%jp0A b=CYUK(ob{wS0;((5noV{c_m#UX&m@JoO(ZO literal 0 HcmV?d00001 diff --git a/docs/assets/images/icon_black.xcf b/docs/assets/images/icon_black.xcf new file mode 100644 index 0000000000000000000000000000000000000000..430e7bafe579b3d563b40f4bbf2faee7ead16848 GIT binary patch literal 36322 zcmeHw34B!5_5YnEne53VlRzLOAqfyjLIQ!vj#@0JXsw!`Hi{Nx5f@Og#-%!L)VNh_ zt%_AEO1IRi1za%IDzw%mR{zx&l}15DD9@*7c~qUW{mM%hxR>m_;)*65Y6KOC_qa){CQ*8@E1b! zqj}Ma;(Z=hh{hxG=HS$IbI+YVXI9;u3+B$mF2m0stX^>8CFjg4Uoiiixibf6RL`Ds z#{6^UUr=7HsP2L}Gp3g}=>M?6_;|)=d_1gN|M~I73(lK<#@u;x%7-;z>yl4x#W(7{ zHE-^P<#XqqaptTA{Kov*vlq;|uw0K%=sVp{AIxh``14Fo*g*G^**)9)2afkxa_-zS zE|_0FV-|k&-02sb%?q4+#{79h&zq@V;h6C+6^&ykX#LrrcqJgl8IAjSuJm{x$W$cs zOA`7S3H|bfer7^HE1{pA(9cDmzvuo1(BW_M`~%{BAXCM@;19Smp`SPpu-pCfp5gXz z8}6jydGY7H!@-vv9>>SVaf^cq_kRa{f4#HcKheRdoNxFG%yDpfZ5)q_fmF~ zb8zzn2cNdq!81;b;wEisQTE_`x{- zwS&L)j)O0LF^=Dg8$7399OgPU-LNnpas6?ZkZDU7CboYZN z<$29WiSAuCEhoh^O008EZklP3*tW%unP#ZO-kg(}ZE7X9y4ja&220HTa%8@#7TeJn zG6Th~o={|}#J+N9Z&M+$&GUT4rd(qCZp`g#%EUfb)6evi*sfMzsVNcrSXsI0BX;+^ zisVHkj6}?MWwc3=CX*(OCR2u)Y#D0uq}Jri5EGJWQzQdTZ>hrIRTydOEB!I5Wfi>_1e(Sw><5E_`X6cull)-fBBa zQcSG+#*IxlD4II8J=!Q4CRTCF_FcmnMH6t705h#b^@{ z>1;9?GQwoZaFZ+bCMb2LKx#~(49421#@ZN&wNb@K*58j`n8>9gTUhKoq=j_JG*zr5FBhjo=}7D+qbK0aZ3C9qB{JNU6x)0sygXM*RUMFk30iR%ro`X0f0c=qEV1Z5m0Ahn9Nvv<`E#(+*wL@!;yx^|FtN;AW9aT4Rbg!78@;f!kL!<< zUfkVVhP5tJA55_>q6*F+l}7tVP(epz6WA77oE&sm4JhSsP}%UA8C8( zTcxD*{kzJ*y6un;%1QnQe9)iFpmbe@6dT*OtCAcd_w_32Wo*i?2LQ>P1HnDyl0i~v z?4;-*uoPRisagt*O@DbXklZ!|?8Z*EL%_#u;fFOqvaA-YNWM`gxyBZJL?rhQ1(%Y; z>LnW&`6`jjZU6(bIUf?qwZkOS*btanrjZ+mgT>k6T|{z2qof;~y_HDLA0cTtK^Ku6 zHP$ZOxZbch7aR_b zNUqoj4k;Cc4!=xS4mvWxIW2SakVm z6H1{Kcc(Q@zvb6|EtY-VYaa|BU+D>%NYQaO{cdlSL^l1ZbzEAOiTD~@SI26htar2y zNj1^HF%N7V0mXb_z0b(jF%n&KRi&8#895A6KC$!5^PBy|JE;L|vlLHQ+Cz9|S$G~J zAl*pC7)U-7AP!+n%tXuz+q|U&YJn|%wlC&J%y*3~hQ45r-qIUiwgX=41r5Sx{=5j2 z#CjG|udv_jF2Dq_M{LW-{IGQ&Ladmbjvf8Gf)d;GonjnPwl*KejwN-~#`gMS0c4wB z)#Ll2*F)$otH&9O))Y!Cc6TrQM%nrziR}!h;a96ZfHbl82=wYc=`FTB1hM1Ledv93 zQl*g@Fp;zeq3BbzZBhu+i}dfTUz8@U=r zmgw0KI=oN!6MH?Sj?%5@E%lcgIiZw-6FN)KSr!0I%6`*RN`(CgRYgc~3buTR;K)Wea zfMqQYkOasv`GEHAv>;ZzTuNwn6styZAEAxatKRYup|wq_*E~v6A;VSQSxRUlrK%6z zL}<6BtD-bb;i^p2zf-nj5f9EV$%meN=*gA-WmxGTSCdLWq56V6^#N^?NxeahdVv%b zfdmzT{)9kx3P53kAS_Ue+Uu}Yt9$t=kK)n2@U3EyvtlD#2I!f1HlCFRR$2)wA#7B{ z8-BH-A4p~C{#LF=*>W%>8fYtE@~(s!LbEN~08^}H+(FQS*=W`stbz!c7Y)6RC{mz? zUsri{m1$SWc9m|b;ZBnZn#I_7Zsgt@pJX#E>#AeDuLw!#jlLiu}z=M&mKF&a)~wZd~1mJFjl`Z{Gpxv3#}EB~%f1v6}d zv9g7Rrtxa1rLopAHc1=JO=Hw_OY^N`Y#J3eHXRZdk7;m{3Ywgp<_giSXie>GtJb3uhyjZLqHd=hduplQQwAO8f(aIP(Nw|W~HTjg%R zvi{A%?glL9R}OVIAnx4P=x#uGdS;Zw@Iw%=x>U^CF_w~7fRdN=Q8-lL7=?!^oUHIz zg(oOHPT^4sCn+4Sa0Gmiix5sU8nk*Yej^7y$L*8xv-{v^+%OFC+J|s5{;?FY+8^Lx zd^{U++Cy+I-jf1(@Vn5IZ5YDXJm}ARTOf!XQx7-G#4I>+plWwj!x`Y&21@;W5nKe% zfuui_0p@xq7~&!?1m@XbU(s_g6t&RucY?uL&&RL~kQ^v6Sm zyWojz_*=4f!$NWwoHVc{@XAXOc9onrIuDZbCOL0F%aZiwUrTS&;Fh3kVyHG6BtN@f z4|j%pOuZgMA)NM7+5xEZlRHv-r;~v0_p$r+CF)Fnf1@+sapb4KZST749Vb2Ye_8|T zL8^1&&Uc!vX~A~n2Fe67o7Y2I1nm;EPskQtWltzsC9a%K7CKz$d?}M~%0v^*#e{1z z+jGaxTk^UUaky!%>2`Kxx;(JLbZ6-ypxL{Qh2c8;aTv9?Pl0*czZkCc_v`734_mn6 zUoC;n{PcaWsXvhooBH8f!OrjUgMANKmqmhKPk(s^c-6_nVDw&=CU*0~L zWLFam_gDWo*F-!K*;Iv)f$8%7JQLX{vIgIZ9=cDi0_$7j6}u`>X(B_mikycXzr*kS z%!8XMUWbsl)39ebLTj&ql{w=DpU70~Sds#ZIXIi|5qvTRJ8nsVZuC_!z3=0bYV5cI zm%qIp?C@J~Qb0G7a{^%A{lF?ujNw?Df?X}R+1GO6_#e3o2WXD zy@NeX@I3txT)5y3XwffYM^&cCMR5P8KAkSofgSmoINd3Exb3Al_U8x*@W!xf&sgyH zHXM9=zLAeH)SCyw)G`x}lWVbKEn+LWieQ?V62YDY*z*EHEMCljF{k#EY(zR?&*OMf zzwpBR)92kBk*{ITk0Gqx0REi)DkQG)*zx_K$T_ehrL4p!HP~?#o^$kTUXz?m$;p(Q zOi9Z0??{=#FoQS2?pzBu09hbo7#NGdxC8`FR^)2L0u9$1^3>J@RhHIrs(P@qZ!uxd zAS7B$fVQU=_jZ_kpzp>y4UB#s==)xrGFD;G^MSv5f&GvYe84I2Aozh(!EaN51MnWC zDlS1kALjKwX!)?IBlK)b09-u-{)05&OjrWafwOd90WLp?eFfn3(CpfBu|I@;IcOn- zT4bSxAg^R9&V%hW7u!KtX7hmaAzwfTyBIY4Ixynk4iNgcJy4{7fITCDYk_ZsLj63* z{5s%S*dBr-bM|1z0_=DgxC6Ka-`tytPqO!7&m`>W01g8$0Dcm92#(m{uQm~tAaI_# zN>`c)iJXGC2uHLiM(}L0yHP6gXvp1wKjz(BcLUm~O-pyT5cyi2Vj?PuAgp#u3c_>c zOoi7e{Gq~!6s}VECx!1S{7B&^3il|CDeP9bL*ZtH8x(dy^?n8+zc0dB68I^?eIKK) z8b+w^{qT#-=*A`70tPx|JK}j;;R&f*k6_;aqW|ON29c&LW3yJ&i-Z`DcROa<4lwO` zF&L+x2h%=rH;mDDfw7O?i1~CbqWvo0gbn#H^8VFyyu;&;Uxm->HAoDeaFxg%kS1nD z;JiN-5rvbt!%fv65r*~em5ICsJ4fGFF^=DZl#=~;KanF5EZ|=ZMSM?2xyoi3@kb!9 zosMt>X+ea-;aefN?a4s^!;p0dop})P4ZUB&Gdey4*-y#IlAJ8b$)Z#sNm>2}DN99M z*>)7_Jj4kyX3$Z<5AOGTMrS`m02m8Mr+XpPU&f`=x#+qfKM%_mIx7!uqrgbrn0dy_ zGgh8XOP-TXO4lLD-(lQf5N2;i6oN)}I@u|7_cP4Q$xx|;+FhYaH=`CAy~rp=D&7NB z>W~VCA~-<{nPA-V6?(&M>JA1=$})u)DI7y+1A7=zDXSH>Dg3&^DnjesK`VwlukeQo z=P8_`a1fzQvy8x$4GMp!aH+zZ6kehb(VIBt1ceh7)+(%2Sfa26uzf1??D}q z2@2;c{Dr~|8Vg^cqd86C9SYZKSbT+sA)Ko)`4ITBo&%A|Z5Rm_Chryq~UL@L!KV?^>LY@1ARR@8Q7vbMHG0Qku}9^L;vf5aRo(8qfM; zjc48L*Lc>iD!hl#ZcWvw)}s_IA+$SkG`Mw^!WXld>(`(WuD5A~>$V(?ZCyZU*QaDK zRj@_j%NfieJR+S5g)e&2m|b`jp?%pCVBX=^3GHkCRAwa3CA1$GsI+nmp^en|nZNj? zpDB%}`2g+aA}_NXf8u50g|;)C`ivy+Q{Z_14|<;aSF5zSYk(ML z4~R8Rb0ZIl-RMI%F_73viO7s6LuAC`y3+Tj7dq*NGTRZrTv5x36_Yk6cFgsMFs=+% zd9rcaYJyc^twaz73P|8Nm7rCD9_azyW*ABDTo{3+&DicDE+=s)vC&Oy+ z4a;p?@K@~EJ_7grmF_ICWP2ozw;O9 zpAw;A%+9csR^=Q9+{$H?UXc$8IaXRJ(b}_O^eEXgA}}uuLg$E2kd@FGK(FC_c%1IS zV=C!HXC^vH74pmc3C(49o=WZLREmB3t|1jVLu5lKgg~MF6 zYa9&O-tL(}kD6VQJ`koj`_cd=8KJTToon`?f{Ns4u6B%ut=mt$WoG_WdrEt9v_k-(&9JDW7FIixe#c;i3W4kw8FJz=e zaJ`U$7RGT14wqbP(+!gcoCnz<5BxL-QbG_o3*taNa0b{uv2>E(7qHhJKraMln*t6W z!o~VWuYf2#m;Yf$ZJj!lh2maqG3a7{egO@-lk5#48Qhmcc@@jWkJ zBDB_A#f@10^m&G>2SI2gW&Qt;17Vu z10%9tYJgV*7Xu@fUIM`PB35xHG8S(Fei!&M;8%g?0zVCW67Yk-M*!ai+z8wT+#k3V zI2U*pf*vCtbWVWBWh11*!+_rat_OY&xF7He;7s8A5em5n4w*&39{^tgjFJv=4)7}A z7T|}0rvTqmCDCgRE%W7@Xxfme9fM@^zO^eCw|#rT?3UvvH-GcY)~j!L;I|)yy?>JK zjknayd@|Z3(U0%`s^4d#g)@G!wLzk9-8wlX-9-H3uKvxgYKd-WKf5w$y8TV(J@CrD zQi*JN=KH7i?_>6+)cn`QcdmRB&b_^M;~yTn`J5>wgUr@IpP`3+wYmB9+23gX`lPYd zg`O}4;^cErKKJB$|I(~?a-$HqgAd$**o#K4<-s<&l_*Y31aSNte>>s8O?Uh>Ca3$` z4FP8`aTonpM}BTDX8H0LZ>|r2OI@OUoMBmAoUF#w#JKU zZ(`wHrx8MCWMhErJ`_N-<-76mhCnt(&TbhD_1W_z4mc|ZBWmC2g#nxcZE}4e2kCJL zsskS^-;U2`=0Yy8D|}Gq{j6Q|W=bxcRdOdTcp>=b(Rql^kohnT92vvWPcU4=#*Tx< zpk^D6j?@O>lCrx;BcPxF

0MSqK;0R0YdN>ThtL>$378lh`%+NCUVZks*@{ApY2A z0>~4%0-N`TAi3D39>f!$5AF8-f)J!1xyEPgnY1j#4ljg+6FJkEGh;aVx*}}Fy1#l6 zIQ@$#>4|WTz36T#Wz39?O=g)6X)T6ef>_C7)(%(|=mRGge!edxFuS3m#Gur`Ce(#Q zKESpS7~lfr18f_EQC|u(!In|zd>x&?4uvJ5?`BvB-WiCV_bK#V?1d+J5ju}#K;{^+ z51RH(KJ-HCkT$U6B$yMtkE8ciEdmp+LuY9YYzW6$sOQ_J!G=)#33{th*vak4>WQ;Dm`>BsT^eFas>74 zSzL)^5`@acHnsJEHL5jNV$aRUz>M-N%44|*-`zp@9&N@$`Iv&X==lOjdA9oP5bH}E zwxtlW-<}^Sf{W5-{g)|bvuYq~BJK|Gfz6a}4I2j+(o|yL`lUPU?p@MC0VJ!#K z&|e9gzgu{#3T6d*1Q;C4@?H#7smAZI03pi{*3jnCUW=<>P7FtE#O@5!m!e0D7 zYY0(JAcnp?n=pkQlt;A~VcIS&MtG!Fg}7Hs5~hBvB?*tw3KC1TFk#v@Elk*=btZnJ zv8AX%0*PSCw-r z%eggJM`*MeBhH*EtxZ_?jw{uTWOHNISagHUaiuzGW-QOa#(Evle*!)%vXOcXbm}tv z0V+d#&B1k&4+v}s9}xHeDg3=Dq$ak#kahR$mf58g@E;#QG7{@vluN?Fg78`_?3JTg zTgN^>mG(vZ>;zVmh;>f$lSaheo|nluh}hCOIr!fGy6lV zww(oiOf2o(4-m|MYq5#t&U+tBdsr{zI4;@=r^lOxCh9x-ktnqA+Y3yrZ|gfSd?O1m znm2uA490hq(TiqGZQqBII6)XS9z*P?wLYyVzE^AOSr|8l>4$*Bwcn!f2MXWd0+j|0 zNV-J>l6DqoDAGbgT(ZU@t@3Lu(s$ArgmktBAw`-s{3zO@fk)961|HdHi^d#9TNrZ` zjkajG5fD~*v<1908U}Yx4qIr5y88WFCHLaEO z=&_6oIqZR4KT!g3`feE2XN6F)P!{<;tF|*}iaegF;0%@8A10N0s6nVt-leSVLdD2#DBu`*D?*oVEJ17Fn`{RzV#hb#{^;Hza%Y zu$+p6O<$>1R0GSIK8`KkE{@b%s_84KZ(vJnsiv>gTB?ENg|vL7uVfZFKGTw_=_|FQ zYG65I4v(egsyqDiJocrf6V=Ruc`Z&^n@l6Dg;oR&tf0LIC)1Rt^rtkzDf?wLn3QbRgq~wLGV;q>=qbtTfKr|~ z9;)TL1vzO2aLaJgQt(;1Yi?mpN+`4kIHBLt<|J$|Q6u~Xc7Oxz0$;QZ{U_3_v9eKQ z7sE*xX=a&zEOb`v$5wyXP_e~2{@7B}LbQd|{jsI>$)hc_Fks6mP2QrV$s^5Lnmme- z8b;_eYf}_z<`Fty3VY;bpd8p=MY1K{Y^_sl6SVK)Fy8CFkl(gXYER!8mN{_lALo*qYAaU@5U)iz1C+ zGf~f|JNAr}ea7Ew)Hm;WC!BT(Pn^7+f7_=+8t=XX<-oF|pI2n`z~kKSC%#9;O{^nV zarIwv8)i+@j-86Be#yby#eb!Qdm3KD_&>XSx#&ONjJg`_1$OW^9WDM^SJQxg{8h92 zUuTyec z_}k;+IDVdQ-xuFr8pl72;|Cpl`H>F3;-omf#=+rR9eic{g|%0f#wq| zIDR6I<1Yd>j&CM22Ja)Kd`kV)0;myCL!h?cI9Hu_C9(biEWxdPAtm*L+~m9!$$cYI zIOA1jZFS-0bY0b8O2ff;XiW

e)9;h6VHi3Uk`jZLZ}Q2L=>K&Lm|Hm)u}HtDcP zX?7SS%LvlByk7>S?1)Gh)=(x`OP}W&^N?}x6Xnf|S(JW2%MU!W{2&u?Wfa66w&8g4ml#ihL;5I643_?U@#NZ%R=}6j0 z#t>+?xK_pC9s))}MoSLOIJDvLNLp`bx}n{MjWPhwNzvAAPOU|!-eQmcoyIlV*=TZe zUf|nPd6AYn8trJmlV(El53+5F0u&0EhOX*RkdXS3bFa?5Q+uK!<&2OsTIwS2B6P-) zDj=IP%6Yizu&1B#b~Hd5FNO3Y%^{o@GXih;gB8AudL2yiCJYz-M3(;P=y|&ZVhuVz zTlR6}9*kx)U)Wl!5)q4X@XZ%|0|wP+N=|Tr1ex~WG`=%~ukYeCt%M@LSGqc{b(JnB z9fBzl2d70OD%j4OKzfwy#P@-~5rVsO-wMJpbyaRx?RHgfSN(QXaA&Sbmpiu1a?dnj zgjTZhmo-67^6|QgxRRWSF0GvEju!4};;uICYUIvikS^z;xca%Pqq~pL{aIpX(mNOA zK6YJsSarOe#O6#JcltP(w|`*6z;sYc;)MI#jjvYuXWJK@+x`5&t8=#xyqm;3bsuCJ z7OL|eH|n&B? zuu9irv5_Q^+>vaNgw~4p%0aj*s80-4 z2&y$S+>2Ajx)>bp!}|3C`!ReBB2U2@^#iBkLQ;SOpm(W?OVH29&-FoLyfQLif{bU% z0Od;q&crP<&M8ax72pE-W*aC#ixD!>nv4AmQ_evPfhuRAh43IV73YDj<2d#qic2f zoxA+q1c=j-4I78&LLfn;bOPC zaU$;FlrG0~@TZB(fy?h-v;BG3;_$&l4)65c`*N{+-!6&lxg%*!yk{(k{c?jVOC(Z% zSLz^kB@tILaf!DpyEw9pEOus!I~N>gAgvB_aLEW6hw@iQUTONY5SY_SNrXJK0&9-x zhSCTp9GQ3!58H#s8N~YcD(;6Rmxb-VSaQrnEXI<{#&&NkIc6jlVaeqH7shc23oRGh zTz+}Ld02dTVA45QXhGmCEHZ{5W?+#KOJf?AR{?v?%!~|SI;H4BE5riJ!+8sF3qj=z z6kjMG{=KFY*2L;*edA&PC$Ka+;sGmYu~B4T)(IywhbN@^E7>rYwzIsQs3u3RO|;Xy zHhNxV2=~F#o5Wr;-VKX%@-9TN%Y_{L#oUep#=*@Uh0n(jwHmpYX>v+zT-*n@YCH>O z0ZO9}TtpTlK(wm?&x<9;5fjoe0QV-1$a67exC>4lr#WxqhU|v~wy!H*}&S&@P<3E~%0@$B<~18AHzoIMO)WfcqNyCUPJne#4$dBhT= zAHGBZegz`ZbcJixqnX?8{+k+)HMak!f_C-OMyD93Dp0NP5C zx~Gx%(f96(-Bp+^tj$1vN8z3%uo}NN7}qic*U2}GOEX_EPX5nPVi_VD>^QfO-O)j@ zp5J%EXe$->!kE*$pQ3~`Q3ivky!c?Dn*`kzxrsk5cGDr^5DAx=xa@-RBAY`b9GSx@ zEQ>f(5{gE|^5H5*D!U-bA|Zq+uerw2zo>h`J>Uq?6qTi;Ovlp^lBLzDH^&*v8BSS) zBoPuwYmO=oj?#rW)|#rDN^BaLW&vi%eR>Gb>(%KLypptIHI5KyM*_%h%N~($B|5!WR_z`d5gq#KVeNh zRDaFYUtJpYziH}aOef8~pB>Y|xQ Date: Mon, 21 Aug 2023 14:31:58 +0100 Subject: [PATCH 139/561] add logo to github pages --- docs/_config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/_config.yml b/docs/_config.yml index fff4ab923c..32f9f2e0dd 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1,3 @@ theme: jekyll-theme-minimal +logo: /assets/images/icon_black.png +show_downloads: true From e441a8cb112a3c13629749ec8c3d65b2d170b10e Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Mon, 21 Aug 2023 16:04:50 +0200 Subject: [PATCH 140/561] perf-counters: Make tests pass on Android (#1653) * perf_counters_gtest: Make test pass on Android Tested on Pixel 3 and Pixel 6. Reduce test to the intersection of what passes on all platforms. Pixel 6 doesn't support BRANCHES, and only supports two perf counters. --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- test/perf_counters_gtest.cc | 48 ++++++++++++++++--------------------- test/perf_counters_test.cc | 3 +-- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index 250ceefadb..54c78635b8 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -21,8 +21,7 @@ using ::testing::Lt; namespace { const char kGenericPerfEvent1[] = "CYCLES"; -const char kGenericPerfEvent2[] = "BRANCHES"; -const char kGenericPerfEvent3[] = "INSTRUCTIONS"; +const char kGenericPerfEvent2[] = "INSTRUCTIONS"; TEST(PerfCountersTest, Init) { EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported); @@ -61,26 +60,24 @@ TEST(PerfCountersTest, NegativeTest) { { // Try sneaking in an outrageous counter, like a fat finger mistake auto counter = PerfCounters::Create( - {kGenericPerfEvent3, "not a counter name", kGenericPerfEvent1}); + {kGenericPerfEvent2, "not a counter name", kGenericPerfEvent1}); EXPECT_EQ(counter.num_counters(), 2); EXPECT_EQ(counter.names(), std::vector( - {kGenericPerfEvent3, kGenericPerfEvent1})); + {kGenericPerfEvent2, kGenericPerfEvent1})); } { - // Finally try a golden input - it should like all them - EXPECT_EQ(PerfCounters::Create( - {kGenericPerfEvent1, kGenericPerfEvent2, kGenericPerfEvent3}) + // Finally try a golden input - it should like both of them + EXPECT_EQ(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}) .num_counters(), - 3); + 2); } { // Add a bad apple in the end of the chain to check the edges - auto counter = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2, - kGenericPerfEvent3, "bad event name"}); - EXPECT_EQ(counter.num_counters(), 3); - EXPECT_EQ(counter.names(), - std::vector({kGenericPerfEvent1, kGenericPerfEvent2, - kGenericPerfEvent3})); + auto counter = PerfCounters::Create( + {kGenericPerfEvent1, kGenericPerfEvent2, "bad event name"}); + EXPECT_EQ(counter.num_counters(), 2); + EXPECT_EQ(counter.names(), std::vector( + {kGenericPerfEvent1, kGenericPerfEvent2})); } } @@ -119,26 +116,25 @@ TEST(PerfCountersTest, Read2Counters) { } TEST(PerfCountersTest, ReopenExistingCounters) { - // This test works in recent and old Intel hardware - // However we cannot make assumptions beyond 3 HW counters + // This test works in recent and old Intel hardware, Pixel 3, and Pixel 6. + // However we cannot make assumptions beyond 2 HW counters due to Pixel 6. if (!PerfCounters::kSupported) { GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; } EXPECT_TRUE(PerfCounters::Initialize()); std::vector kMetrics({kGenericPerfEvent1}); - std::vector counters(3); + std::vector counters(2); for (auto& counter : counters) { counter = PerfCounters::Create(kMetrics); } PerfCounterValues values(1); EXPECT_TRUE(counters[0].Snapshot(&values)); EXPECT_TRUE(counters[1].Snapshot(&values)); - EXPECT_TRUE(counters[2].Snapshot(&values)); } TEST(PerfCountersTest, CreateExistingMeasurements) { // The test works (i.e. causes read to fail) for the assumptions - // about hardware capabilities (i.e. small number (3) hardware + // about hardware capabilities (i.e. small number (2) hardware // counters) at this date, // the same as previous test ReopenExistingCounters. if (!PerfCounters::kSupported) { @@ -151,7 +147,7 @@ TEST(PerfCountersTest, CreateExistingMeasurements) { // we could use libpfm to query for the hardware limits on this // particular platform. const int kMaxCounters = 10; - const int kMinValidCounters = 3; + const int kMinValidCounters = 2; // Let's use a ubiquitous counter that is guaranteed to work // on all platforms @@ -229,7 +225,7 @@ void measure(size_t threadcount, PerfCounterValues* before, // the scopes overlap, and we need to explicitly control the scope of the // threadpool. auto counters = - PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent3}); + PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}); for (auto& t : threads) t = std::thread(work); counters.Snapshot(before); for (auto& t : threads) t.join(); @@ -281,16 +277,14 @@ TEST(PerfCountersTest, HardwareLimits) { EXPECT_TRUE(PerfCounters::Initialize()); // Taken from `perf list`, but focusses only on those HW events that actually - // were reported when running `sudo perf stat -a sleep 10`. All HW events - // listed in the first command not reported in the second seem to not work. - // This is sad as we don't really get to test the grouping here (groups can - // contain up to 6 members)... + // were reported when running `sudo perf stat -a sleep 10`, intersected over + // several platforms. All HW events listed in the first command not reported + // in the second seem to not work. This is sad as we don't really get to test + // the grouping here (groups can contain up to 6 members)... std::vector counter_names{ "cycles", // leader "instructions", // - "branches", // "branch-misses", // - "cache-misses", // }; // In the off-chance that some of these values are not supported, diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index 5419947fff..f2ef9be23b 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -61,7 +61,6 @@ ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_WithPauseResume\",$"}}); static void CheckSimple(Results const& e) { CHECK_COUNTER_VALUE(e, double, "CYCLES", GT, 0); - CHECK_COUNTER_VALUE(e, double, "BRANCHES", GT, 0.0); } double withoutPauseResumeInstrCount = 0.0; @@ -88,7 +87,7 @@ int main(int argc, char* argv[]) { if (!benchmark::internal::PerfCounters::kSupported) { return 0; } - benchmark::FLAGS_benchmark_perf_counters = "CYCLES,BRANCHES,INSTRUCTIONS"; + benchmark::FLAGS_benchmark_perf_counters = "CYCLES,INSTRUCTIONS"; benchmark::internal::PerfCounters::Initialize(); RunOutputTests(argc, argv); From e73915667c21faccd7019c6da8ab083b0264db13 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Mon, 21 Aug 2023 16:35:42 +0200 Subject: [PATCH 141/561] State: Initialize counters with kAvgIteration in constructor (#1652) * State: Initialize counters with kAvgIteration in constructor Previously, `counters` was updated in `PauseTiming()` with `counters[name] += Counter(measurement, kAvgIteration)`. The first `counters[name]` call inserts a counter with no flags. There is no `operator+=` for `Counter`, so the insertion is done by converting the `Counter` to a `double`, then constructing a `Counter` to insert from the `double`, which drops the flags. Pre-insert the `Counter` with the correct flags, then only update `Counter::value`. Introduced in 1c64a36 ([perf-counters] Fix pause/resume (#1643)). * perf_counters_test.cc: Don't divide by iterations Perf counters are now divided by iterations, so dividing again in the test is wrong. * State: Fix shadowed param error * benchmark.cc: Fix clang-tidy error --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/benchmark.cc | 19 ++++++++++++++++--- test/perf_counters_test.cc | 17 ++++++----------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 974cde6cf4..6139e59d05 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -179,6 +179,17 @@ State::State(std::string name, IterationCount max_iters, BM_CHECK_LT(thread_index_, threads_) << "thread_index must be less than threads"; + // Add counters with correct flag now. If added with `counters[name]` in + // `PauseTiming`, a new `Counter` will be inserted the first time, which + // won't have the flag. Inserting them now also reduces the allocations + // during the benchmark. + if (perf_counters_measurement_) { + for (const std::string& counter_name : + perf_counters_measurement_->names()) { + counters[counter_name] = Counter(0.0, Counter::kAvgIterations); + } + } + // Note: The use of offsetof below is technically undefined until C++17 // because State is not a standard layout type. However, all compilers // currently provide well-defined behavior as an extension (which is @@ -227,9 +238,11 @@ void State::PauseTiming() { BM_CHECK(false) << "Perf counters read the value failed."; } for (const auto& name_and_measurement : measurements) { - auto name = name_and_measurement.first; - auto measurement = name_and_measurement.second; - counters[name] += Counter(measurement, Counter::kAvgIterations); + const std::string& name = name_and_measurement.first; + const double measurement = name_and_measurement.second; + // Counter was inserted with `kAvgIterations` flag by the constructor. + assert(counters.find(name) != counters.end()); + counters[name].value += measurement; } } } diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index f2ef9be23b..b0a3ab0619 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -66,22 +66,17 @@ static void CheckSimple(Results const& e) { double withoutPauseResumeInstrCount = 0.0; double withPauseResumeInstrCount = 0.0; -static void CheckInstrCount(double* counter, Results const& e) { - BM_CHECK_GT(e.NumIterations(), 0); - *counter = e.GetAs("INSTRUCTIONS") / e.NumIterations(); +static void SaveInstrCountWithoutResume(Results const& e) { + withoutPauseResumeInstrCount = e.GetAs("INSTRUCTIONS"); } -static void CheckInstrCountWithoutResume(Results const& e) { - CheckInstrCount(&withoutPauseResumeInstrCount, e); -} - -static void CheckInstrCountWithResume(Results const& e) { - CheckInstrCount(&withPauseResumeInstrCount, e); +static void SaveInstrCountWithResume(Results const& e) { + withPauseResumeInstrCount = e.GetAs("INSTRUCTIONS"); } CHECK_BENCHMARK_RESULTS("BM_Simple", &CheckSimple); -CHECK_BENCHMARK_RESULTS("BM_WithoutPauseResume", &CheckInstrCountWithoutResume); -CHECK_BENCHMARK_RESULTS("BM_WithPauseResume", &CheckInstrCountWithResume); +CHECK_BENCHMARK_RESULTS("BM_WithoutPauseResume", &SaveInstrCountWithoutResume); +CHECK_BENCHMARK_RESULTS("BM_WithPauseResume", &SaveInstrCountWithResume); int main(int argc, char* argv[]) { if (!benchmark::internal::PerfCounters::kSupported) { From 9c65aebb266f35b035c5d2a46a19b795d6bf23c8 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 24 Aug 2023 11:04:09 +0200 Subject: [PATCH 142/561] perf_counters: Initialize once only when needed (#1656) * perf_counters: Initialize once only when needed This works around some performance problems running Android under QEMU. Calling `pfm_initialize` was very slow, and was called during dynamic initialization (before `main` or when loaded as a shared library). This happened whenever benchmark was linked, even if no benchmarks were run. Instead, call `pfm_initialize` at most once, and only when one of: 1. `PerfCounters::Initialize` is called 2. `PerfCounters::Create` is called with a non-empty counter list 3. `PerfCounters::IsCounterSupported` is called The return value of the first `pfm_initialize()` is saved and returned from all subsequent `PerfCounters::Initialize` calls. * perf_counters: Make success var const * InitLibPfmOnce: Inline function --- src/perf_counters.cc | 15 ++++++++++++++- src/perf_counters.h | 2 -- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 3980ea053e..417acdb18f 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -57,9 +57,18 @@ size_t PerfCounterValues::Read(const std::vector& leaders) { const bool PerfCounters::kSupported = true; -bool PerfCounters::Initialize() { return pfm_initialize() == PFM_SUCCESS; } +// Initializes libpfm only on the first call. Returns whether that single +// initialization was successful. +bool PerfCounters::Initialize() { + // Function-scope static gets initialized only once on first call. + static const bool success = []() { + return pfm_initialize() == PFM_SUCCESS; + }(); + return success; +} bool PerfCounters::IsCounterSupported(const std::string& name) { + Initialize(); perf_event_attr_t attr; std::memset(&attr, 0, sizeof(attr)); pfm_perf_encode_arg_t arg; @@ -73,6 +82,10 @@ bool PerfCounters::IsCounterSupported(const std::string& name) { PerfCounters PerfCounters::Create( const std::vector& counter_names) { + if (!counter_names.empty()) { + Initialize(); + } + // Valid counters will populate these arrays but we start empty std::vector valid_names; std::vector counter_ids; diff --git a/src/perf_counters.h b/src/perf_counters.h index 152a6f2561..bf5eb6bc3a 100644 --- a/src/perf_counters.h +++ b/src/perf_counters.h @@ -190,8 +190,6 @@ class BENCHMARK_EXPORT PerfCountersMeasurement final { PerfCounterValues end_values_; }; -BENCHMARK_UNUSED static bool perf_init_anchor = PerfCounters::Initialize(); - } // namespace internal } // namespace benchmark From dfc8a92abc88a9d630a9f8e01c678fedde4c3090 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 24 Aug 2023 14:43:50 +0200 Subject: [PATCH 143/561] test: Use gtest_main only when needed (#1657) * test: Use gtest_main only when needed There are two types of tests. `*_gtest.cc` files use `gtest` and `gtest_main`. `*_test.cc` files define their own main. Only depend on `gtest`/`gtest_main` when needed. This is similar to what `CMakeLists.txt` does. * comment-only: gunit => gtest * Fix typo --- test/BUILD | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/test/BUILD b/test/BUILD index 8262d080fa..ea34fd4646 100644 --- a/test/BUILD +++ b/test/BUILD @@ -49,29 +49,48 @@ cc_library( ], ) +# Tests that use gtest. These rely on `gtest_main`. [ cc_test( name = test_src[:-len(".cc")], size = "small", srcs = [test_src], - args = TEST_ARGS + PER_SRC_TEST_ARGS.get(test_src, []), copts = select({ "//:windows": [], "//conditions:default": TEST_COPTS, }) + PER_SRC_COPTS.get(test_src, []), deps = [ - ":output_test_helper", "//:benchmark", "//:benchmark_internal_headers", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", ], + ) + for test_src in glob(["*_gtest.cc"]) +] + +# Tests that do not use gtest. These have their own `main` defined. +[ + cc_test( + name = test_src[:-len(".cc")], + size = "small", + srcs = [test_src], + args = TEST_ARGS + PER_SRC_TEST_ARGS.get(test_src, []), + copts = select({ + "//:windows": [], + "//conditions:default": TEST_COPTS, + }) + PER_SRC_COPTS.get(test_src, []), + deps = [ + ":output_test_helper", + "//:benchmark", + "//:benchmark_internal_headers", + ], # FIXME: Add support for assembly tests to bazel. # See Issue #556 # https://github.com/google/benchmark/issues/556 ) for test_src in glob( - ["*test.cc"], + ["*_test.cc"], exclude = [ "*_assembly_test.cc", "cxx03_test.cc", @@ -93,8 +112,6 @@ cc_test( ":output_test_helper", "//:benchmark", "//:benchmark_internal_headers", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", ], ) From 6dd50bb6061d9bf9c7053032334ccb72f6438d09 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Thu, 24 Aug 2023 16:05:09 +0200 Subject: [PATCH 144/561] StatisticsMedian: Fix bug Previously, this could return the wrong result when there was an even number of elements. There were two `nth_element` calls. The second call could change elements in `[center2, end])`, which was where `center` pointed. Therefore, `*center` sometimes had the wrong value after the second `nth_element` call. Rewrite to use `max_element` instead of the second call to `nth_element`. This avoids modifying the vector. --- src/statistics.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/statistics.cc b/src/statistics.cc index c4b54b271f..a0e828e8c1 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -42,13 +42,12 @@ double StatisticsMedian(const std::vector& v) { auto center = copy.begin() + v.size() / 2; std::nth_element(copy.begin(), center, copy.end()); - // did we have an odd number of samples? - // if yes, then center is the median - // it no, then we are looking for the average between center and the value - // before + // Did we have an odd number of samples? If yes, then center is the median. + // If not, then we are looking for the average between center and the value + // before. Instead of resorting, we just look for the max value before it. + // (Since `copy` is partially sorted.) if (v.size() % 2 == 1) return *center; - auto center2 = copy.begin() + v.size() / 2 - 1; - std::nth_element(copy.begin(), center2, copy.end()); + auto center2 = std::max_element(copy.begin(), center); return (*center + *center2) / 2.0; } From 78220d6f0d9b20d13cf671c64df029ca6c2f6b18 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Fri, 25 Aug 2023 09:58:30 +0100 Subject: [PATCH 145/561] tweak comment wording --- src/statistics.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/statistics.cc b/src/statistics.cc index a0e828e8c1..844e926895 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -44,8 +44,9 @@ double StatisticsMedian(const std::vector& v) { // Did we have an odd number of samples? If yes, then center is the median. // If not, then we are looking for the average between center and the value - // before. Instead of resorting, we just look for the max value before it. - // (Since `copy` is partially sorted.) + // before. Instead of resorting, we just look for the max value before it, + // which is not necessarily the element immediately preceding `center` Since + // `copy` is only partially sorted by `nth_element`. if (v.size() % 2 == 1) return *center; auto center2 = std::max_element(copy.begin(), center); return (*center + *center2) / 2.0; From 344117638c8ff7e239044fd0fa7085839fc03021 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 31 Aug 2023 13:16:50 +0100 Subject: [PATCH 146/561] bump version to 1.8.3 --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68889a0f75..ffd7deeb2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.10...3.22) -project (benchmark VERSION 1.8.2 LANGUAGES CXX) +project (benchmark VERSION 1.8.3 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index cf07c3ef5a..37a5f5de5e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,4 +1,4 @@ -module(name = "google_benchmark", version="1.8.2") +module(name = "google_benchmark", version="1.8.3") bazel_dep(name = "bazel_skylib", version = "1.4.1") bazel_dep(name = "platforms", version = "0.0.6") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 2a5e65dba4..642d78a7f4 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -69,7 +69,7 @@ def my_benchmark(state): "State", ] -__version__ = "1.8.2" +__version__ = "1.8.3" class __OptionMaker: From c9106a79fa2aae95bc3c790f0b3aa1cf8a27b86f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20Gergely?= Date: Tue, 26 Sep 2023 13:31:24 +0200 Subject: [PATCH 147/561] Audit MSVC references in cmake files to consider clang++ (#1669) There are three major compilers on Windows targeting the MSVC ABI (i.e. linking with microsofts STL etc.): - `MSVC` - `clang-cl` aka clang with the MSVC compatible CLI - `clang++` aka clang with gcc compatible CLI The cmake variable `MSVC` is only set for the first two as it defined in terms of the CLI interface provided: > Set to true when the compiler is some version of Microsoft Visual > C++ or another compiler simulating the Visual C++ cl command-line syntax. (from cmake docs) For many of the tests in the library its the ABI that matters not the cmdline, so check `CMAKE_CXX_SIMULATE_ID` too, if it is `MSVC` the current compiler is targeting the MSVC ABI. This handles `clang++` --- AUTHORS | 1 + CMakeLists.txt | 8 ++++---- CONTRIBUTORS | 1 + test/CMakeLists.txt | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index d08c1fdb87..2170e46fd4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,6 +31,7 @@ Evgeny Safronov Fabien Pichot Federico Ficarelli Felix Homann +Gergely Meszaros Gergő Szitár Google Inc. Henrique Bucher diff --git a/CMakeLists.txt b/CMakeLists.txt index ffd7deeb2f..5757283296 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ if(BENCHMARK_FORCE_WERROR) set(BENCHMARK_ENABLE_WERROR ON) endif(BENCHMARK_FORCE_WERROR) -if(NOT MSVC) +if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) option(BENCHMARK_BUILD_32_BITS "Build a 32 bit version of the library." OFF) else() set(BENCHMARK_BUILD_32_BITS OFF CACHE BOOL "Build a 32 bit version of the library - unsupported when using MSVC)" FORCE) @@ -45,7 +45,7 @@ option(BENCHMARK_ENABLE_LIBPFM "Enable performance counters provided by libpfm" set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) -if(MSVC) +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # As of CMake 3.18, CMAKE_SYSTEM_PROCESSOR is not set properly for MSVC and # cross-compilation (e.g. Host=x86_64, target=aarch64) requires using the # undocumented, but working variable. @@ -66,7 +66,7 @@ function(should_enable_assembly_tests) return() endif() endif() - if (MSVC) + if (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") return() elseif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") return() @@ -128,7 +128,7 @@ if (BENCHMARK_BUILD_32_BITS) add_required_cxx_compiler_flag(-m32) endif() -if (MSVC) +if (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") set(BENCHMARK_CXX_STANDARD 14) else() set(BENCHMARK_CXX_STANDARD 11) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 95bcad019b..b3d1d58199 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -51,6 +51,7 @@ Fanbo Meng Federico Ficarelli Felix Homann Geoffrey Martin-Noble +Gergely Meszaros Gergő Szitár Hannes Hauswedell Henrique Bucher diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fd88131988..ac1a00f582 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -183,7 +183,7 @@ compile_output_test(memory_manager_test) add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s) # MSVC does not allow to set the language standard to C++98/03. -if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) compile_benchmark_test(cxx03_test) set_target_properties(cxx03_test PROPERTIES From 7736df03049c362c7275f7573de6d6a685630e0a Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Tue, 26 Sep 2023 14:43:23 +0200 Subject: [PATCH 148/561] Make json and csv output consistent. (#1662) * Make json and csv output consistent. Currently, the --benchmark_format=csv option does not output the correct value for the cv statistics. Also, the json output should not contain a time unit for the cv statistics. * fix formatting * undo json change --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/csv_reporter.cc | 14 +++++++++++--- test/output_test_helper.cc | 1 + test/reporter_output_test.cc | 2 +- test/user_counters_tabular_test.cc | 4 ++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 7b56da107e..4b39e2c52f 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -122,13 +122,21 @@ void CSVReporter::PrintRunData(const Run& run) { } Out << ","; - Out << run.GetAdjustedRealTime() << ","; - Out << run.GetAdjustedCPUTime() << ","; + if (run.run_type != Run::RT_Aggregate || + run.aggregate_unit == StatisticUnit::kTime) { + Out << run.GetAdjustedRealTime() << ","; + Out << run.GetAdjustedCPUTime() << ","; + } else { + assert(run.aggregate_unit == StatisticUnit::kPercentage); + Out << run.real_accumulated_time << ","; + Out << run.cpu_accumulated_time << ","; + } // Do not print timeLabel on bigO and RMS report if (run.report_big_o) { Out << GetBigOString(run.complexity); - } else if (!run.report_rms) { + } else if (!run.report_rms && + run.aggregate_unit != StatisticUnit::kPercentage) { Out << GetTimeUnitString(run.time_unit); } Out << ","; diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index 25673700aa..265f28aae7 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -65,6 +65,7 @@ SubMap& GetSubstitutions() { {"%csv_us_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",us,,,,,"}, {"%csv_ms_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ms,,,,,"}, {"%csv_s_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",s,,,,,"}, + {"%csv_cv_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",,,,,,"}, {"%csv_bytes_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns," + safe_dec_re + ",,,,"}, {"%csv_items_report", diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 2eb545a8de..657a9a1079 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -1088,7 +1088,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_UserPercentStats/iterations:5/repeats:3/" {"^\"BM_UserPercentStats/iterations:5/repeats:3/" "manual_time_stddev\",%csv_report$"}, {"^\"BM_UserPercentStats/iterations:5/repeats:3/" - "manual_time_\",%csv_report$"}}); + "manual_time_\",%csv_cv_report$"}}); // ========================================================================= // // ------------------------- Testing StrEscape JSON ------------------------ // diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index c98b769af2..e7ada657b2 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -330,7 +330,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Tabular/repeats:2/threads:1_stddev\",%csv_report," "%float,%float,%float,%float,%float,%float$"}}); ADD_CASES(TC_CSVOut, - {{"^\"BM_Counters_Tabular/repeats:2/threads:1_cv\",%csv_report," + {{"^\"BM_Counters_Tabular/repeats:2/threads:1_cv\",%csv_cv_report," "%float,%float,%float,%float,%float,%float$"}}); ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Tabular/repeats:2/threads:2\",%csv_report," @@ -348,7 +348,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Tabular/repeats:2/threads:2_stddev\",%csv_report," "%float,%float,%float,%float,%float,%float$"}}); ADD_CASES(TC_CSVOut, - {{"^\"BM_Counters_Tabular/repeats:2/threads:2_cv\",%csv_report," + {{"^\"BM_Counters_Tabular/repeats:2/threads:2_cv\",%csv_cv_report," "%float,%float,%float,%float,%float,%float$"}}); // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() From ca8d0f7b613ac915cd6b161ab01b7be449d1e1cd Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Sun, 8 Oct 2023 11:08:46 +0100 Subject: [PATCH 149/561] correct cli param in docs --- include/benchmark/benchmark.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index e3857e717f..23103571bb 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -341,7 +341,7 @@ BENCHMARK_EXPORT BenchmarkReporter* CreateDefaultDisplayReporter(); // The second and third overload use the specified 'display_reporter' and // 'file_reporter' respectively. 'file_reporter' will write to the file // specified -// by '--benchmark_output'. If '--benchmark_output' is not given the +// by '--benchmark_out'. If '--benchmark_out' is not given the // 'file_reporter' is ignored. // // RETURNS: The number of matching benchmarks. From 682153afda11d0d376413abfac2e81552a6e7b0f Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Fri, 13 Oct 2023 16:59:20 +0200 Subject: [PATCH 150/561] Update bazel.yml (#1671) Updated actions/checkout@v4 Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 1cdc38c97e..a669cda84c 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -14,7 +14,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] bzlmod: [false, true] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: mount bazel cache uses: actions/cache@v3 From ea3c3f983b8d7d67acf98ea090eae57a0130434e Mon Sep 17 00:00:00 2001 From: Ming Zero <32085760+zm1060@users.noreply.github.com> Date: Mon, 16 Oct 2023 23:19:17 +0800 Subject: [PATCH 151/561] Fix building on MinGW: default `WINVER` is too old (#1681) MinGW defaults `WINVER` to something very old, while benchmark requires features gated by `WINVER = 0x0600`, so manually set update to that. --- src/sysinfo.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 922e83ac92..ae6dba90d7 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -15,6 +15,10 @@ #include "internal_macros.h" #ifdef BENCHMARK_OS_WINDOWS +#if !defined(WINVER) || WINVER < 0x0600 +#undef WINVER +#define WINVER 0x0600 +#endif // WINVER handling #include #undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA #include From dc9b229b78fe198ab9c6ee572d0be4b19287a1f5 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:47:29 +0100 Subject: [PATCH 152/561] add name to clang format job --- .github/workflows/clang-format-lint.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 77ce1f8cd4..328fe36cc7 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -4,7 +4,8 @@ on: pull_request: {} jobs: - build: + job: + name: check-clang-format runs-on: ubuntu-latest steps: From 365bf7602b569b97e8c35ab34fb0350563959ca3 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 17 Oct 2023 16:50:22 +0100 Subject: [PATCH 153/561] fix format in src/sysinfo --- src/sysinfo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index ae6dba90d7..64aa15e072 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -18,7 +18,7 @@ #if !defined(WINVER) || WINVER < 0x0600 #undef WINVER #define WINVER 0x0600 -#endif // WINVER handling +#endif // WINVER handling #include #undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA #include From f30c99a7c861e8cabc6d3d9c0b60a4f218c7f87a Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Tue, 17 Oct 2023 18:13:59 +0200 Subject: [PATCH 154/561] Increase the kMaxIterations limit (#1668) * Increase the kMaxIterations limit This fixes #1663. Note that as a result of this change, the columns in the console output can become misaligned if the actual iteration count is too high. This will be dealt with in a separate commit. * Fix failing test on Windows * Fix formatting --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/benchmark_runner.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index f7ae424397..f5cd3e644b 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -64,7 +64,7 @@ MemoryManager* memory_manager = nullptr; namespace { -static constexpr IterationCount kMaxIterations = 1000000000; +static constexpr IterationCount kMaxIterations = 1000000000000; const double kDefaultMinTime = std::strtod(::benchmark::kDefaultMinTimeStr, /*p_end*/ nullptr); @@ -325,8 +325,8 @@ IterationCount BenchmarkRunner::PredictNumItersNeeded( // So what seems to be the sufficiently-large iteration count? Round up. const IterationCount max_next_iters = static_cast( - std::lround(std::max(multiplier * static_cast(i.iters), - static_cast(i.iters) + 1.0))); + std::llround(std::max(multiplier * static_cast(i.iters), + static_cast(i.iters) + 1.0))); // But we do have *some* limits though.. const IterationCount next_iters = std::min(max_next_iters, kMaxIterations); From 7495f83e2a6e1aa69592fcda6e5c6c1b0b4fa118 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Fri, 20 Oct 2023 08:51:32 -0400 Subject: [PATCH 155/561] Set -Wno-unused-variable for tests (#1682) We used assert() a lot in tests and that can cause build breakages in some of the opt builds (since assert() are removed) it's not practical to sprinkle "(void)" everywhere so I think setting this warning option is the best option for now. --- test/BUILD | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/BUILD b/test/BUILD index ea34fd4646..22b7dba4b9 100644 --- a/test/BUILD +++ b/test/BUILD @@ -18,6 +18,9 @@ TEST_COPTS = [ # "-Wshorten-64-to-32", "-Wfloat-equal", "-fstrict-aliasing", + ## assert() are used a lot in tests upstream, which may be optimised out leading to + ## unused-variable warning. + "-Wno-unused-variable", ] # Some of the issues with DoNotOptimize only occur when optimization is enabled From 6a16cee366cb85174c2d27e4dfe3a74c8b81abf6 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 23 Oct 2023 08:54:08 +0000 Subject: [PATCH 156/561] Add no-unititialized to tests (#1683) --- test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ac1a00f582..c262236419 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,6 +5,8 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) include(CheckCXXCompilerFlag) +add_cxx_compiler_flag(-Wno-unused-variable) + # NOTE: Some tests use `` to perform the test. Therefore we must # strip -DNDEBUG from the default CMake flags in DEBUG mode. string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) From 5893034e46da730ba9e8ecdc27fe77745fb1511f Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 23 Oct 2023 14:04:39 +0200 Subject: [PATCH 157/561] Add Python 3.12 support (#1676) * Add Python 3.12 support tag * Bump nanobind to latest stable v1.6.2 tag * Add PyPI trusted publishing to GitHub workflow, add Python 3.12 wheel builds Trusted publishing has been available since v1.8.0 of the pypa-publish action. It enables password-less authentication and wheel uploads from the wheel upload job. `cibuildwheel` was bumped to v2.16.2 to allow Python 3.12 wheel builds. More info on trusted publishing: https://github.com/marketplace/actions/pypi-publish#trusted-publishing The Windows distribution was reverted to `latest` in the OS matrix, since the discovery problem of MSVC was fixed in a Bazel patch release. * Bump nanobind to stable v1.7.0 tag --- .github/workflows/test_bindings.yml | 11 ++++++----- .github/workflows/wheels.yml | 18 ++++++++---------- bazel/benchmark_deps.bzl | 2 +- pyproject.toml | 1 + 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index e01bb7b014..a287f72901 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -13,17 +13,18 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest, windows-2019 ] + os: [ ubuntu-latest, macos-latest, windows-latest ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: 3.11 - - name: Install GBM Python bindings on ${{ matrix.os}} - run: - python -m pip install wheel . + - name: Install GBM Python bindings on ${{ matrix.os }} + run: | + python -m pip install --upgrade pip setuptools wheel + python -m pip install . - name: Run bindings example on ${{ matrix.os }} run: python bindings/python/google_benchmark/example.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 1f73bff4b2..b7c4da7134 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Python 3.11 uses: actions/setup-python@v4 @@ -33,11 +33,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-2019] + os: [ubuntu-latest, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up QEMU if: runner.os == 'Linux' @@ -46,9 +46,9 @@ jobs: platforms: all - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.14.1 + uses: pypa/cibuildwheel@v2.16.2 env: - CIBW_BUILD: 'cp38-* cp39-* cp310-* cp311-*' + CIBW_BUILD: 'cp38-* cp39-* cp310-* cp311-* cp312-*' CIBW_SKIP: "*-musllinux_*" CIBW_TEST_SKIP: "*-macosx_arm64" CIBW_ARCHS_LINUX: x86_64 aarch64 @@ -67,13 +67,11 @@ jobs: name: Publish google-benchmark wheels to PyPI needs: [build_sdist, build_wheels] runs-on: ubuntu-latest + permissions: + id-token: write steps: - uses: actions/download-artifact@v3 with: name: dist path: dist - - - uses: pypa/gh-action-pypi-publish@v1.6.4 - with: - user: __token__ - password: ${{ secrets.PYPI_PASSWORD }} + - uses: pypa/gh-action-pypi-publish@v1.8.10 diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 667065f9b7..07c329390c 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -48,7 +48,7 @@ def benchmark_deps(): new_git_repository( name = "nanobind", remote = "https://github.com/wjakob/nanobind.git", - tag = "v1.4.0", + tag = "v1.7.0", build_file = "@//bindings/python:nanobind.BUILD", recursive_init_submodules = True, ) diff --git a/pyproject.toml b/pyproject.toml index fe8770bc78..2db11fcb93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Software Development :: Testing", "Topic :: System :: Benchmark", ] From e45585a4b8e75c28479fa4107182c28172799640 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 24 Oct 2023 14:04:12 +0200 Subject: [PATCH 158/561] Change nanobind linkage to response file approach on macOS (#1638) * Change nanobind linkage to response file approach This change needs https://github.com/bazelbuild/bazel/pull/18952 to be merged first. Fixes macOS linkage of GBM's nanobind bindings on macOS by supplying a linker response file instead of `-undefined dynamic_lookup`. The latter has since been deprecated on macOS. * Fix bazel_skylib checksum, bump skylib version in MODULE.bazel * Bump Bazel to version 6.4.0 for linker response file support --- .github/install_bazel.sh | 2 +- MODULE.bazel | 2 +- bazel/benchmark_deps.bzl | 17 +++++++++-------- bindings/python/nanobind.BUILD | 18 +++++++++++++++++- bindings/python/python_headers.BUILD | 4 ++++ setup.py | 7 +++---- 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/.github/install_bazel.sh b/.github/install_bazel.sh index 2b1f4e726c..d07db0e758 100644 --- a/.github/install_bazel.sh +++ b/.github/install_bazel.sh @@ -5,7 +5,7 @@ if ! bazel version; then fi echo "Installing wget and downloading $arch Bazel binary from GitHub releases." yum install -y wget - wget "https://github.com/bazelbuild/bazel/releases/download/6.3.0/bazel-6.3.0-linux-$arch" -O /usr/local/bin/bazel + wget "https://github.com/bazelbuild/bazel/releases/download/6.4.0/bazel-6.4.0-linux-$arch" -O /usr/local/bin/bazel chmod +x /usr/local/bin/bazel else # bazel is installed for the correct architecture diff --git a/MODULE.bazel b/MODULE.bazel index 37a5f5de5e..a8930590d0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module(name = "google_benchmark", version="1.8.3") -bazel_dep(name = "bazel_skylib", version = "1.4.1") +bazel_dep(name = "bazel_skylib", version = "1.4.2") bazel_dep(name = "platforms", version = "0.0.6") bazel_dep(name = "rules_foreign_cc", version = "0.9.0") bazel_dep(name = "rules_cc", version = "0.0.6") diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 07c329390c..8fda013116 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -7,26 +7,27 @@ def benchmark_deps(): if "bazel_skylib" not in native.existing_rules(): http_archive( name = "bazel_skylib", - sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", + sha256 = "66ffd9315665bfaafc96b52278f57c7e2dd09f5ede279ea6d39b2be471e7e3aa", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz", ], ) if "rules_foreign_cc" not in native.existing_rules(): http_archive( name = "rules_foreign_cc", - sha256 = "bcd0c5f46a49b85b384906daae41d277b3dc0ff27c7c752cc51e43048a58ec83", - strip_prefix = "rules_foreign_cc-0.7.1", - url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.7.1.tar.gz", + sha256 = "2a4d07cd64b0719b39a7c12218a3e507672b82a97b98c6a89d38565894cf7c51", + strip_prefix = "rules_foreign_cc-0.9.0", + url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.9.0.tar.gz", ) if "rules_python" not in native.existing_rules(): http_archive( name = "rules_python", - url = "https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz", - sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0", + sha256 = "0a8003b044294d7840ac7d9d73eef05d6ceb682d7516781a4ec62eeb34702578", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.24.0/rules_python-0.24.0.tar.gz", + strip_prefix = "rules_python-0.24.0", ) if "com_google_absl" not in native.existing_rules(): diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD index cd9faf99bb..2852019502 100644 --- a/bindings/python/nanobind.BUILD +++ b/bindings/python/nanobind.BUILD @@ -1,3 +1,12 @@ +licenses(["notice"]) + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "symboltable", + srcs = ["cmake/darwin-ld-cpython.sym"], +) + cc_library( name = "nanobind", srcs = glob([ @@ -12,6 +21,13 @@ cc_library( "ext/robin_map/include/tsl/*.h", ], ), + linkopts = select({ + "@platforms//os:macos": ["-Wl,@$(location :cmake/darwin-ld-cpython.sym)"], + "//conditions:default": [], + }), + additional_linker_inputs = select({ + "@platforms//os:macos": [":cmake/darwin-ld-cpython.sym"], + "//conditions:default": [], + }), deps = ["@python_headers"], - visibility = ["//visibility:public"], ) diff --git a/bindings/python/python_headers.BUILD b/bindings/python/python_headers.BUILD index 9c34cf6ca4..8f139f8621 100644 --- a/bindings/python/python_headers.BUILD +++ b/bindings/python/python_headers.BUILD @@ -1,3 +1,7 @@ +licenses(["notice"]) + +package(default_visibility = ["//visibility:public"]) + cc_library( name = "python_headers", hdrs = glob(["**/*.h"]), diff --git a/setup.py b/setup.py index b02a6a7012..0593bb9c7d 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,9 @@ class BuildBazelExtension(build_ext.build_ext): def run(self): for ext in self.extensions: self.bazel_build(ext) - build_ext.build_ext.run(self) + super().run() + # explicitly call `bazel shutdown` for graceful exit + self.spawn(["bazel", "shutdown"]) def bazel_build(self, ext: BazelExtension): """Runs the bazel build to create the package.""" @@ -98,9 +100,6 @@ def bazel_build(self, ext: BazelExtension): ext_dest_path = Path(self.get_ext_fullpath(ext.name)) shutil.copyfile(ext_bazel_bin_path, ext_dest_path) - # explicitly call `bazel shutdown` for graceful exit - self.spawn(["bazel", "shutdown"]) - setuptools.setup( cmdclass=dict(build_ext=BuildBazelExtension), From 698d1dc8c321d0797487e7988825f3f43c1d86b0 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Wed, 25 Oct 2023 13:12:18 +0200 Subject: [PATCH 159/561] Reapply size optimizations for clang & MSVC, LTO for Mac+Linux (#1685) * Reapply size optimization for clang, equivalent options for MSVC Working towards cross-platform optimal nanobind building configurations. * Add LTO back to non-Windows builds The Windows case (the option name is "/GL") is more complicated, since there, the compiler options also need to be passed to the linker if LTO is enabled. Since we are gating the linker options on platform at the moment instead of compiler, we need to implement a Bazel boolean flag for the case "Platform == MacOS && Compiler == AnyOf(gcc, clang)". --- bindings/python/nanobind.BUILD | 42 ++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD index 2852019502..c7edfb2b93 100644 --- a/bindings/python/nanobind.BUILD +++ b/bindings/python/nanobind.BUILD @@ -2,18 +2,40 @@ licenses(["notice"]) package(default_visibility = ["//visibility:public"]) -filegroup( - name = "symboltable", - srcs = ["cmake/darwin-ld-cpython.sym"], +config_setting( + name = "msvc_compiler", + flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"}, ) cc_library( name = "nanobind", srcs = glob([ - "src/*.cpp" + "src/*.cpp", ]), - copts = ["-fexceptions"], - includes = ["include", "ext/robin_map/include"], + additional_linker_inputs = select({ + "@platforms//os:macos": [":cmake/darwin-ld-cpython.sym"], + "//conditions:default": [], + }), + copts = select({ + ":msvc_compiler": [ + "/EHsc", # exceptions + "/Os", # size optimizations + ], + # these should work on both clang and gcc. + "//conditions:default": [ + "-fexceptions", + "-flto", + "-Os", + ], + }), + includes = [ + "ext/robin_map/include", + "include", + ], + linkopts = select({ + "@platforms//os:macos": ["-Wl,@$(location :cmake/darwin-ld-cpython.sym)"], + "//conditions:default": [], + }), textual_hdrs = glob( [ "include/**/*.h", @@ -21,13 +43,5 @@ cc_library( "ext/robin_map/include/tsl/*.h", ], ), - linkopts = select({ - "@platforms//os:macos": ["-Wl,@$(location :cmake/darwin-ld-cpython.sym)"], - "//conditions:default": [], - }), - additional_linker_inputs = select({ - "@platforms//os:macos": [":cmake/darwin-ld-cpython.sym"], - "//conditions:default": [], - }), deps = ["@python_headers"], ) From b219e18b91b4279a582abb9195a1fefc5d8838c0 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Fri, 27 Oct 2023 13:49:43 +0200 Subject: [PATCH 160/561] [bindings] Add LTO builds on Windows+MSVC (#1687) * Add LTO builds on Windows+MSVC Gates the MSVC switches behind an `@bazel_skylib:selects` statement. This is a first experiment from best guesses and studying the MSVC docs. * Fix misleading inline comment --- bindings/python/nanobind.BUILD | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD index c7edfb2b93..c6fa1c6d64 100644 --- a/bindings/python/nanobind.BUILD +++ b/bindings/python/nanobind.BUILD @@ -2,11 +2,21 @@ licenses(["notice"]) package(default_visibility = ["//visibility:public"]) +load("@bazel_skylib//lib:selects.bzl", "selects") + config_setting( name = "msvc_compiler", flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"}, ) +selects.config_setting_group( + name = "winplusmsvc", + match_all = [ + "@platforms//os:windows", + ":msvc_compiler", + ], +) + cc_library( name = "nanobind", srcs = glob([ @@ -20,6 +30,7 @@ cc_library( ":msvc_compiler": [ "/EHsc", # exceptions "/Os", # size optimizations + "/GL", # LTO / whole program optimization ], # these should work on both clang and gcc. "//conditions:default": [ @@ -33,7 +44,8 @@ cc_library( "include", ], linkopts = select({ - "@platforms//os:macos": ["-Wl,@$(location :cmake/darwin-ld-cpython.sym)"], + ":winplusmsvc": ["/LTGC"], # Windows + MSVC. + "@platforms//os:macos": ["-Wl,@$(location :cmake/darwin-ld-cpython.sym)"], # Apple. "//conditions:default": [], }), textual_hdrs = glob( From b93f5a592972b9017539cf15a5d299149c1cc2f4 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 30 Oct 2023 16:35:37 +0100 Subject: [PATCH 161/561] Add pre-commit config and GitHub Actions job (#1688) * Add pre-commit config and GitHub Actions job Contains the following hooks: * buildifier - for formatting and linting Bazel files. * mypy, ruff, isort, black - for Python typechecking, import hygiene, static analysis, and formatting. The pylint CI job was changed to be a pre-commit CI job, where pre-commit is bootstrapped via Python. Pylint is currently no longer part of the code checks, but can be re-added if requested. The reason to drop was that it does not play nicely with pre-commit, and lots of its functionality and responsibilities are actually covered in ruff. * Add dev extra to pyproject.toml for development installs * Clarify that pre-commit contains only Python and Bazel hooks * Add one-line docstrings to Bazel modules * Apply buildifier pre-commit fixes to Bazel files * Apply pre-commit fixes to Python files * Supply --profile=black to isort to prevent conflicts * Fix nanobind build file formatting * Add tooling configs to `pyproject.toml` In particular, set line length 80 for all Python files. * Reformat all Python files to line length 80, fix return type annotations Also ignores the `tools/compare.py` and `tools/gbench/report.py` files for mypy, since they emit a barrage of errors which we can deal with later. The errors are mostly related to dynamic classmethod definition. --- .github/workflows/pre-commit.yml | 39 + .github/workflows/pylint.yml | 28 - .pre-commit-config.yaml | 26 + .ycm_extra_conf.py | 193 ++- BUILD.bazel | 27 +- MODULE.bazel | 14 +- WORKSPACE | 6 +- bazel/benchmark_deps.bzl | 6 +- bindings/python/BUILD | 2 +- bindings/python/build_defs.bzl | 4 + bindings/python/google_benchmark/BUILD | 1 - bindings/python/google_benchmark/__init__.py | 16 +- bindings/python/google_benchmark/example.py | 5 +- bindings/python/nanobind.BUILD | 4 +- pyproject.toml | 39 + setup.py | 14 +- tools/BUILD.bazel | 4 +- tools/compare.py | 429 +++-- tools/gbench/__init__.py | 8 +- tools/gbench/report.py | 1628 +++++++++++------- tools/gbench/util.py | 97 +- tools/strip_asm.py | 118 +- 22 files changed, 1628 insertions(+), 1080 deletions(-) create mode 100644 .github/workflows/pre-commit.yml delete mode 100644 .github/workflows/pylint.yml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000000..f78a90d874 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,39 @@ +name: python + Bazel pre-commit checks + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + pre-commit: + runs-on: ubuntu-latest + env: + MYPY_CACHE_DIR: "${{ github.workspace }}/.cache/mypy" + RUFF_CACHE_DIR: "${{ github.workspace }}/.cache/ruff" + PRE_COMMIT_HOME: "${{ github.workspace }}/.cache/pre-commit" + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + cache: 'pip' + cache-dependency-path: pyproject.toml + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e ".[dev]" + - name: Cache pre-commit tools + uses: actions/cache@v3 + with: + path: | + ${{ env.MYPY_CACHE_DIR }} + ${{ env.RUFF_CACHE_DIR }} + ${{ env.PRE_COMMIT_HOME }} + key: ${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}-linter-cache + - name: Run pre-commit checks + run: | + pre-commit run --all-files --verbose --show-diff-on-failure diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml deleted file mode 100644 index c6939b50f3..0000000000 --- a/.github/workflows/pylint.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: pylint - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - pylint: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.8 - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pylint pylint-exit conan - - - name: Run pylint - run: | - pylint `find . -name '*.py'|xargs` || pylint-exit $? diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..94ae788f0b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,26 @@ +repos: + - repo: https://github.com/keith/pre-commit-buildifier + rev: 6.3.3.1 + hooks: + - id: buildifier + - id: buildifier-lint + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.6.1 + hooks: + - id: mypy + types_or: [ python, pyi ] + args: [ "--ignore-missing-imports", "--scripts-are-modules" ] + - repo: https://github.com/psf/black + rev: 23.10.1 + hooks: + - id: black + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + args: [--profile, black] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.3 + hooks: + - id: ruff + args: [ --fix, --exit-non-zero-on-fix ] \ No newline at end of file diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index 5649ddcc74..caf257f054 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -1,25 +1,30 @@ import os + import ycm_core # These are the compilation flags that will be used in case there's no # compilation database set (by default, one is not set). # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. flags = [ -'-Wall', -'-Werror', -'-pedantic-errors', -'-std=c++0x', -'-fno-strict-aliasing', -'-O3', -'-DNDEBUG', -# ...and the same thing goes for the magic -x option which specifies the -# language that the files to be compiled are written in. This is mostly -# relevant for c++ headers. -# For a C project, you would set this to 'c' instead of 'c++'. -'-x', 'c++', -'-I', 'include', -'-isystem', '/usr/include', -'-isystem', '/usr/local/include', + "-Wall", + "-Werror", + "-pedantic-errors", + "-std=c++0x", + "-fno-strict-aliasing", + "-O3", + "-DNDEBUG", + # ...and the same thing goes for the magic -x option which specifies the + # language that the files to be compiled are written in. This is mostly + # relevant for c++ headers. + # For a C project, you would set this to 'c' instead of 'c++'. + "-x", + "c++", + "-I", + "include", + "-isystem", + "/usr/include", + "-isystem", + "/usr/local/include", ] @@ -29,87 +34,87 @@ # # Most projects will NOT need to set this to anything; you can just change the # 'flags' list of compilation flags. Notice that YCM itself uses that approach. -compilation_database_folder = '' +compilation_database_folder = "" -if os.path.exists( compilation_database_folder ): - database = ycm_core.CompilationDatabase( compilation_database_folder ) +if os.path.exists(compilation_database_folder): + database = ycm_core.CompilationDatabase(compilation_database_folder) else: - database = None + database = None + +SOURCE_EXTENSIONS = [".cc"] -SOURCE_EXTENSIONS = [ '.cc' ] def DirectoryOfThisScript(): - return os.path.dirname( os.path.abspath( __file__ ) ) - - -def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): - if not working_directory: - return list( flags ) - new_flags = [] - make_next_absolute = False - path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] - for flag in flags: - new_flag = flag - - if make_next_absolute: - make_next_absolute = False - if not flag.startswith( '/' ): - new_flag = os.path.join( working_directory, flag ) - - for path_flag in path_flags: - if flag == path_flag: - make_next_absolute = True - break - - if flag.startswith( path_flag ): - path = flag[ len( path_flag ): ] - new_flag = path_flag + os.path.join( working_directory, path ) - break - - if new_flag: - new_flags.append( new_flag ) - return new_flags - - -def IsHeaderFile( filename ): - extension = os.path.splitext( filename )[ 1 ] - return extension in [ '.h', '.hxx', '.hpp', '.hh' ] - - -def GetCompilationInfoForFile( filename ): - # The compilation_commands.json file generated by CMake does not have entries - # for header files. So we do our best by asking the db for flags for a - # corresponding source file, if any. If one exists, the flags for that file - # should be good enough. - if IsHeaderFile( filename ): - basename = os.path.splitext( filename )[ 0 ] - for extension in SOURCE_EXTENSIONS: - replacement_file = basename + extension - if os.path.exists( replacement_file ): - compilation_info = database.GetCompilationInfoForFile( - replacement_file ) - if compilation_info.compiler_flags_: - return compilation_info - return None - return database.GetCompilationInfoForFile( filename ) - - -def FlagsForFile( filename, **kwargs ): - if database: - # Bear in mind that compilation_info.compiler_flags_ does NOT return a - # python list, but a "list-like" StringVec object - compilation_info = GetCompilationInfoForFile( filename ) - if not compilation_info: - return None - - final_flags = MakeRelativePathsInFlagsAbsolute( - compilation_info.compiler_flags_, - compilation_info.compiler_working_dir_ ) - else: - relative_to = DirectoryOfThisScript() - final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) - - return { - 'flags': final_flags, - 'do_cache': True - } + return os.path.dirname(os.path.abspath(__file__)) + + +def MakeRelativePathsInFlagsAbsolute(flags, working_directory): + if not working_directory: + return list(flags) + new_flags = [] + make_next_absolute = False + path_flags = ["-isystem", "-I", "-iquote", "--sysroot="] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith("/"): + new_flag = os.path.join(working_directory, flag) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith(path_flag): + path = flag[len(path_flag) :] + new_flag = path_flag + os.path.join(working_directory, path) + break + + if new_flag: + new_flags.append(new_flag) + return new_flags + + +def IsHeaderFile(filename): + extension = os.path.splitext(filename)[1] + return extension in [".h", ".hxx", ".hpp", ".hh"] + + +def GetCompilationInfoForFile(filename): + # The compilation_commands.json file generated by CMake does not have entries + # for header files. So we do our best by asking the db for flags for a + # corresponding source file, if any. If one exists, the flags for that file + # should be good enough. + if IsHeaderFile(filename): + basename = os.path.splitext(filename)[0] + for extension in SOURCE_EXTENSIONS: + replacement_file = basename + extension + if os.path.exists(replacement_file): + compilation_info = database.GetCompilationInfoForFile( + replacement_file + ) + if compilation_info.compiler_flags_: + return compilation_info + return None + return database.GetCompilationInfoForFile(filename) + + +def FlagsForFile(filename, **kwargs): + if database: + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = GetCompilationInfoForFile(filename) + if not compilation_info: + return None + + final_flags = MakeRelativePathsInFlagsAbsolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_, + ) + else: + relative_to = DirectoryOfThisScript() + final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to) + + return {"flags": final_flags, "do_cache": True} diff --git a/BUILD.bazel b/BUILD.bazel index 60d31d2f2e..64188344c1 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -45,28 +45,28 @@ cc_library( "include/benchmark/benchmark.h", "include/benchmark/export.h", ], - linkopts = select({ - ":windows": ["-DEFAULTLIB:shlwapi.lib"], - "//conditions:default": ["-pthread"], - }), copts = select({ ":windows": [], "//conditions:default": ["-Werror=old-style-cast"], }), - strip_include_prefix = "include", - visibility = ["//visibility:public"], - # Only static linking is allowed; no .so will be produced. - # Using `defines` (i.e. not `local_defines`) means that no - # dependent rules need to bother about defining the macro. - linkstatic = True, defines = [ "BENCHMARK_STATIC_DEFINE", ] + select({ ":perfcounters": ["HAVE_LIBPFM"], "//conditions:default": [], }), + linkopts = select({ + ":windows": ["-DEFAULTLIB:shlwapi.lib"], + "//conditions:default": ["-pthread"], + }), + # Only static linking is allowed; no .so will be produced. + # Using `defines` (i.e. not `local_defines`) means that no + # dependent rules need to bother about defining the macro. + linkstatic = True, + strip_include_prefix = "include", + visibility = ["//visibility:public"], deps = select({ - ":perfcounters": ["@libpfm//:libpfm"], + ":perfcounters": ["@libpfm"], "//conditions:default": [], }), ) @@ -74,7 +74,10 @@ cc_library( cc_library( name = "benchmark_main", srcs = ["src/benchmark_main.cc"], - hdrs = ["include/benchmark/benchmark.h", "include/benchmark/export.h"], + hdrs = [ + "include/benchmark/benchmark.h", + "include/benchmark/export.h", + ], strip_include_prefix = "include", visibility = ["//visibility:public"], deps = [":benchmark"], diff --git a/MODULE.bazel b/MODULE.bazel index a8930590d0..8dd3d83193 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,11 +1,16 @@ -module(name = "google_benchmark", version="1.8.3") +module( + name = "google_benchmark", + version = "1.8.3", +) bazel_dep(name = "bazel_skylib", version = "1.4.2") bazel_dep(name = "platforms", version = "0.0.6") bazel_dep(name = "rules_foreign_cc", version = "0.9.0") bazel_dep(name = "rules_cc", version = "0.0.6") + bazel_dep(name = "rules_python", version = "0.24.0", dev_dependency = True) -bazel_dep(name = "googletest", version = "1.12.1", repo_name = "com_google_googletest", dev_dependency = True) +bazel_dep(name = "googletest", version = "1.12.1", dev_dependency = True, repo_name = "com_google_googletest") + bazel_dep(name = "libpfm", version = "4.11.0") # Register a toolchain for Python 3.9 to be able to build numpy. Python @@ -18,7 +23,8 @@ python.toolchain(python_version = "3.9") pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) pip.parse( - hub_name="tools_pip_deps", + hub_name = "tools_pip_deps", python_version = "3.9", - requirements_lock="//tools:requirements.txt") + requirements_lock = "//tools:requirements.txt", +) use_repo(pip, "tools_pip_deps") diff --git a/WORKSPACE b/WORKSPACE index 833590f289..a9cf5b379f 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,11 +8,11 @@ load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_depende rules_foreign_cc_dependencies() -load("@rules_python//python:pip.bzl", pip3_install="pip_install") +load("@rules_python//python:pip.bzl", pip3_install = "pip_install") pip3_install( - name = "tools_pip_deps", - requirements = "//tools:requirements.txt", + name = "tools_pip_deps", + requirements = "//tools:requirements.txt", ) new_local_repository( diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 8fda013116..91a3674224 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -1,5 +1,9 @@ -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +""" +This file contains the Bazel build dependencies for Google Benchmark (both C++ source and Python bindings). +""" + load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") def benchmark_deps(): """Loads dependencies required to build Google Benchmark.""" diff --git a/bindings/python/BUILD b/bindings/python/BUILD index 9559a76b30..d61dcb12a1 100644 --- a/bindings/python/BUILD +++ b/bindings/python/BUILD @@ -1,3 +1,3 @@ exports_files(glob(["*.BUILD"])) -exports_files(["build_defs.bzl"]) +exports_files(["build_defs.bzl"]) diff --git a/bindings/python/build_defs.bzl b/bindings/python/build_defs.bzl index 009820afd0..b0c1b0f580 100644 --- a/bindings/python/build_defs.bzl +++ b/bindings/python/build_defs.bzl @@ -1,3 +1,7 @@ +""" +This file contains some build definitions for C++ extensions used in the Google Benchmark Python bindings. +""" + _SHARED_LIB_SUFFIX = { "//conditions:default": ".so", "//:windows": ".dll", diff --git a/bindings/python/google_benchmark/BUILD b/bindings/python/google_benchmark/BUILD index 89ec76e0d5..f516a693eb 100644 --- a/bindings/python/google_benchmark/BUILD +++ b/bindings/python/google_benchmark/BUILD @@ -37,4 +37,3 @@ py_test( ":google_benchmark", ], ) - diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 642d78a7f4..63b4f6616a 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -32,23 +32,22 @@ def my_benchmark(state): from google_benchmark import _benchmark from google_benchmark._benchmark import ( Counter, - kNanosecond, + State, kMicrosecond, kMillisecond, + kNanosecond, kSecond, - oNone, o1, + oAuto, + oLambda, + oLogN, oN, - oNSquared, oNCubed, - oLogN, oNLogN, - oAuto, - oLambda, - State, + oNone, + oNSquared, ) - __all__ = [ "register", "main", @@ -97,7 +96,6 @@ def __getattr__(self, builder_name): # The function that get returned on @option.range(start=0, limit=1<<5). def __builder_method(*args, **kwargs): - # The decorator that get called, either with the benchmared function # or the previous Options def __decorator(func_or_options): diff --git a/bindings/python/google_benchmark/example.py b/bindings/python/google_benchmark/example.py index d95a0438d6..b5b2f88ff3 100644 --- a/bindings/python/google_benchmark/example.py +++ b/bindings/python/google_benchmark/example.py @@ -38,6 +38,7 @@ def sum_million(state): while state: sum(range(1_000_000)) + @benchmark.register def pause_timing(state): """Pause timing every iteration.""" @@ -85,7 +86,9 @@ def custom_counters(state): # Set a counter as a rate. state.counters["foo_rate"] = Counter(num_foo, Counter.kIsRate) # Set a counter as an inverse of rate. - state.counters["foo_inv_rate"] = Counter(num_foo, Counter.kIsRate | Counter.kInvert) + state.counters["foo_inv_rate"] = Counter( + num_foo, Counter.kIsRate | Counter.kInvert + ) # Set a counter as a thread-average quantity. state.counters["foo_avg"] = Counter(num_foo, Counter.kAvgThreads) # There's also a combined flag: diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD index c6fa1c6d64..9874b80d1f 100644 --- a/bindings/python/nanobind.BUILD +++ b/bindings/python/nanobind.BUILD @@ -1,9 +1,9 @@ +load("@bazel_skylib//lib:selects.bzl", "selects") + licenses(["notice"]) package(default_visibility = ["//visibility:public"]) -load("@bazel_skylib//lib:selects.bzl", "selects") - config_setting( name = "msvc_compiler", flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"}, diff --git a/pyproject.toml b/pyproject.toml index 2db11fcb93..0bac140bb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,11 @@ dependencies = [ "absl-py>=0.7.1", ] +[project.optional-dependencies] +dev = [ + "pre-commit>=3.3.3", +] + [project.urls] Homepage = "https://github.com/google/benchmark" Documentation = "https://github.com/google/benchmark/tree/main/docs" @@ -49,3 +54,37 @@ where = ["bindings/python"] [tool.setuptools.dynamic] version = { attr = "google_benchmark.__version__" } readme = { file = "README.md", content-type = "text/markdown" } + +[tool.black] +# Source https://github.com/psf/black#configuration-format +include = "\\.pyi?$" +line-length = 80 +target-version = ["py311"] + +# Black-compatible settings for isort +# See https://black.readthedocs.io/en/stable/ +[tool.isort] +line_length = "80" +profile = "black" + +[tool.mypy] +check_untyped_defs = true +disallow_incomplete_defs = true +pretty = true +python_version = "3.11" +strict_optional = false +warn_unreachable = true + +[[tool.mypy.overrides]] +module = ["yaml"] +ignore_missing_imports = true + +[tool.ruff] +# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. +select = ["E", "F", "W"] +ignore = [ + # whitespace before colon (:), rely on black for formatting (in particular, allow spaces before ":" in list/array slices) + "E203", + # line too long, rely on black for reformatting of these, since sometimes URLs or comments can be longer + "E501", +] diff --git a/setup.py b/setup.py index 0593bb9c7d..f4700a025a 100644 --- a/setup.py +++ b/setup.py @@ -4,11 +4,11 @@ import shutil import sysconfig from pathlib import Path +from typing import Generator import setuptools from setuptools.command import build_ext - PYTHON_INCLUDE_PATH_PLACEHOLDER = "" IS_WINDOWS = platform.system() == "Windows" @@ -16,14 +16,14 @@ @contextlib.contextmanager -def temp_fill_include_path(fp: str): +def temp_fill_include_path(fp: str) -> Generator[None, None, None]: """Temporarily set the Python include path in a file.""" with open(fp, "r+") as f: try: content = f.read() replaced = content.replace( PYTHON_INCLUDE_PATH_PLACEHOLDER, - Path(sysconfig.get_paths()['include']).as_posix(), + Path(sysconfig.get_paths()["include"]).as_posix(), ) f.seek(0) f.write(replaced) @@ -57,7 +57,7 @@ def run(self): # explicitly call `bazel shutdown` for graceful exit self.spawn(["bazel", "shutdown"]) - def bazel_build(self, ext: BazelExtension): + def bazel_build(self, ext: BazelExtension) -> None: """Runs the bazel build to create the package.""" with temp_fill_include_path("WORKSPACE"): temp_path = Path(self.build_temp) @@ -93,9 +93,11 @@ def bazel_build(self, ext: BazelExtension): self.spawn(bazel_argv) - shared_lib_suffix = '.dll' if IS_WINDOWS else '.so' + shared_lib_suffix = ".dll" if IS_WINDOWS else ".so" ext_name = ext.target_name + shared_lib_suffix - ext_bazel_bin_path = temp_path / 'bazel-bin' / ext.relpath / ext_name + ext_bazel_bin_path = ( + temp_path / "bazel-bin" / ext.relpath / ext_name + ) ext_dest_path = Path(self.get_ext_fullpath(ext.name)) shutil.copyfile(ext_bazel_bin_path, ext_dest_path) diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index d25caa79ae..0e36472801 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -4,8 +4,8 @@ py_library( name = "gbench", srcs = glob(["gbench/*.py"]), deps = [ - requirement("numpy"), - requirement("scipy"), + requirement("numpy"), + requirement("scipy"), ], ) diff --git a/tools/compare.py b/tools/compare.py index e5eeb247e6..3cc9e5eb4a 100755 --- a/tools/compare.py +++ b/tools/compare.py @@ -1,17 +1,20 @@ #!/usr/bin/env python3 -import unittest +# type: ignore + """ compare.py - versatile benchmark output compare tool """ import argparse -from argparse import ArgumentParser import json -import sys import os +import sys +import unittest +from argparse import ArgumentParser + import gbench -from gbench import util, report +from gbench import report, util def check_inputs(in1, in2, flags): @@ -20,163 +23,203 @@ def check_inputs(in1, in2, flags): """ in1_kind, in1_err = util.classify_input_file(in1) in2_kind, in2_err = util.classify_input_file(in2) - output_file = util.find_benchmark_flag('--benchmark_out=', flags) - output_type = util.find_benchmark_flag('--benchmark_out_format=', flags) - if in1_kind == util.IT_Executable and in2_kind == util.IT_Executable and output_file: - print(("WARNING: '--benchmark_out=%s' will be passed to both " - "benchmarks causing it to be overwritten") % output_file) + output_file = util.find_benchmark_flag("--benchmark_out=", flags) + output_type = util.find_benchmark_flag("--benchmark_out_format=", flags) + if ( + in1_kind == util.IT_Executable + and in2_kind == util.IT_Executable + and output_file + ): + print( + ( + "WARNING: '--benchmark_out=%s' will be passed to both " + "benchmarks causing it to be overwritten" + ) + % output_file + ) if in1_kind == util.IT_JSON and in2_kind == util.IT_JSON: # When both sides are JSON the only supported flag is # --benchmark_filter= - for flag in util.remove_benchmark_flags('--benchmark_filter=', flags): - print("WARNING: passing %s has no effect since both " - "inputs are JSON" % flag) - if output_type is not None and output_type != 'json': - print(("ERROR: passing '--benchmark_out_format=%s' to 'compare.py`" - " is not supported.") % output_type) + for flag in util.remove_benchmark_flags("--benchmark_filter=", flags): + print( + "WARNING: passing %s has no effect since both " + "inputs are JSON" % flag + ) + if output_type is not None and output_type != "json": + print( + ( + "ERROR: passing '--benchmark_out_format=%s' to 'compare.py`" + " is not supported." + ) + % output_type + ) sys.exit(1) def create_parser(): parser = ArgumentParser( - description='versatile benchmark output compare tool') + description="versatile benchmark output compare tool" + ) parser.add_argument( - '-a', - '--display_aggregates_only', - dest='display_aggregates_only', + "-a", + "--display_aggregates_only", + dest="display_aggregates_only", action="store_true", help="If there are repetitions, by default, we display everything - the" - " actual runs, and the aggregates computed. Sometimes, it is " - "desirable to only view the aggregates. E.g. when there are a lot " - "of repetitions. Do note that only the display is affected. " - "Internally, all the actual runs are still used, e.g. for U test.") + " actual runs, and the aggregates computed. Sometimes, it is " + "desirable to only view the aggregates. E.g. when there are a lot " + "of repetitions. Do note that only the display is affected. " + "Internally, all the actual runs are still used, e.g. for U test.", + ) parser.add_argument( - '--no-color', - dest='color', + "--no-color", + dest="color", default=True, action="store_false", - help="Do not use colors in the terminal output" + help="Do not use colors in the terminal output", ) parser.add_argument( - '-d', - '--dump_to_json', - dest='dump_to_json', - help="Additionally, dump benchmark comparison output to this file in JSON format.") + "-d", + "--dump_to_json", + dest="dump_to_json", + help="Additionally, dump benchmark comparison output to this file in JSON format.", + ) utest = parser.add_argument_group() utest.add_argument( - '--no-utest', - dest='utest', + "--no-utest", + dest="utest", default=True, action="store_false", - help="The tool can do a two-tailed Mann-Whitney U test with the null hypothesis that it is equally likely that a randomly selected value from one sample will be less than or greater than a randomly selected value from a second sample.\nWARNING: requires **LARGE** (no less than {}) number of repetitions to be meaningful!\nThe test is being done by default, if at least {} repetitions were done.\nThis option can disable the U Test.".format(report.UTEST_OPTIMAL_REPETITIONS, report.UTEST_MIN_REPETITIONS)) + help="The tool can do a two-tailed Mann-Whitney U test with the null hypothesis that it is equally likely that a randomly selected value from one sample will be less than or greater than a randomly selected value from a second sample.\nWARNING: requires **LARGE** (no less than {}) number of repetitions to be meaningful!\nThe test is being done by default, if at least {} repetitions were done.\nThis option can disable the U Test.".format( + report.UTEST_OPTIMAL_REPETITIONS, report.UTEST_MIN_REPETITIONS + ), + ) alpha_default = 0.05 utest.add_argument( "--alpha", - dest='utest_alpha', + dest="utest_alpha", default=alpha_default, type=float, - help=("significance level alpha. if the calculated p-value is below this value, then the result is said to be statistically significant and the null hypothesis is rejected.\n(default: %0.4f)") % - alpha_default) + help=( + "significance level alpha. if the calculated p-value is below this value, then the result is said to be statistically significant and the null hypothesis is rejected.\n(default: %0.4f)" + ) + % alpha_default, + ) subparsers = parser.add_subparsers( - help='This tool has multiple modes of operation:', - dest='mode') + help="This tool has multiple modes of operation:", dest="mode" + ) parser_a = subparsers.add_parser( - 'benchmarks', - help='The most simple use-case, compare all the output of these two benchmarks') - baseline = parser_a.add_argument_group( - 'baseline', 'The benchmark baseline') + "benchmarks", + help="The most simple use-case, compare all the output of these two benchmarks", + ) + baseline = parser_a.add_argument_group("baseline", "The benchmark baseline") baseline.add_argument( - 'test_baseline', - metavar='test_baseline', - type=argparse.FileType('r'), + "test_baseline", + metavar="test_baseline", + type=argparse.FileType("r"), nargs=1, - help='A benchmark executable or JSON output file') + help="A benchmark executable or JSON output file", + ) contender = parser_a.add_argument_group( - 'contender', 'The benchmark that will be compared against the baseline') + "contender", "The benchmark that will be compared against the baseline" + ) contender.add_argument( - 'test_contender', - metavar='test_contender', - type=argparse.FileType('r'), + "test_contender", + metavar="test_contender", + type=argparse.FileType("r"), nargs=1, - help='A benchmark executable or JSON output file') + help="A benchmark executable or JSON output file", + ) parser_a.add_argument( - 'benchmark_options', - metavar='benchmark_options', + "benchmark_options", + metavar="benchmark_options", nargs=argparse.REMAINDER, - help='Arguments to pass when running benchmark executables') + help="Arguments to pass when running benchmark executables", + ) parser_b = subparsers.add_parser( - 'filters', help='Compare filter one with the filter two of benchmark') - baseline = parser_b.add_argument_group( - 'baseline', 'The benchmark baseline') + "filters", help="Compare filter one with the filter two of benchmark" + ) + baseline = parser_b.add_argument_group("baseline", "The benchmark baseline") baseline.add_argument( - 'test', - metavar='test', - type=argparse.FileType('r'), + "test", + metavar="test", + type=argparse.FileType("r"), nargs=1, - help='A benchmark executable or JSON output file') + help="A benchmark executable or JSON output file", + ) baseline.add_argument( - 'filter_baseline', - metavar='filter_baseline', + "filter_baseline", + metavar="filter_baseline", type=str, nargs=1, - help='The first filter, that will be used as baseline') + help="The first filter, that will be used as baseline", + ) contender = parser_b.add_argument_group( - 'contender', 'The benchmark that will be compared against the baseline') + "contender", "The benchmark that will be compared against the baseline" + ) contender.add_argument( - 'filter_contender', - metavar='filter_contender', + "filter_contender", + metavar="filter_contender", type=str, nargs=1, - help='The second filter, that will be compared against the baseline') + help="The second filter, that will be compared against the baseline", + ) parser_b.add_argument( - 'benchmark_options', - metavar='benchmark_options', + "benchmark_options", + metavar="benchmark_options", nargs=argparse.REMAINDER, - help='Arguments to pass when running benchmark executables') + help="Arguments to pass when running benchmark executables", + ) parser_c = subparsers.add_parser( - 'benchmarksfiltered', - help='Compare filter one of first benchmark with filter two of the second benchmark') - baseline = parser_c.add_argument_group( - 'baseline', 'The benchmark baseline') + "benchmarksfiltered", + help="Compare filter one of first benchmark with filter two of the second benchmark", + ) + baseline = parser_c.add_argument_group("baseline", "The benchmark baseline") baseline.add_argument( - 'test_baseline', - metavar='test_baseline', - type=argparse.FileType('r'), + "test_baseline", + metavar="test_baseline", + type=argparse.FileType("r"), nargs=1, - help='A benchmark executable or JSON output file') + help="A benchmark executable or JSON output file", + ) baseline.add_argument( - 'filter_baseline', - metavar='filter_baseline', + "filter_baseline", + metavar="filter_baseline", type=str, nargs=1, - help='The first filter, that will be used as baseline') + help="The first filter, that will be used as baseline", + ) contender = parser_c.add_argument_group( - 'contender', 'The benchmark that will be compared against the baseline') + "contender", "The benchmark that will be compared against the baseline" + ) contender.add_argument( - 'test_contender', - metavar='test_contender', - type=argparse.FileType('r'), + "test_contender", + metavar="test_contender", + type=argparse.FileType("r"), nargs=1, - help='The second benchmark executable or JSON output file, that will be compared against the baseline') + help="The second benchmark executable or JSON output file, that will be compared against the baseline", + ) contender.add_argument( - 'filter_contender', - metavar='filter_contender', + "filter_contender", + metavar="filter_contender", type=str, nargs=1, - help='The second filter, that will be compared against the baseline') + help="The second filter, that will be compared against the baseline", + ) parser_c.add_argument( - 'benchmark_options', - metavar='benchmark_options', + "benchmark_options", + metavar="benchmark_options", nargs=argparse.REMAINDER, - help='Arguments to pass when running benchmark executables') + help="Arguments to pass when running benchmark executables", + ) return parser @@ -191,16 +234,16 @@ def main(): assert not unknown_args benchmark_options = args.benchmark_options - if args.mode == 'benchmarks': + if args.mode == "benchmarks": test_baseline = args.test_baseline[0].name test_contender = args.test_contender[0].name - filter_baseline = '' - filter_contender = '' + filter_baseline = "" + filter_contender = "" # NOTE: if test_baseline == test_contender, you are analyzing the stdev - description = 'Comparing %s to %s' % (test_baseline, test_contender) - elif args.mode == 'filters': + description = "Comparing %s to %s" % (test_baseline, test_contender) + elif args.mode == "filters": test_baseline = args.test[0].name test_contender = args.test[0].name filter_baseline = args.filter_baseline[0] @@ -209,9 +252,12 @@ def main(): # NOTE: if filter_baseline == filter_contender, you are analyzing the # stdev - description = 'Comparing %s to %s (from %s)' % ( - filter_baseline, filter_contender, args.test[0].name) - elif args.mode == 'benchmarksfiltered': + description = "Comparing %s to %s (from %s)" % ( + filter_baseline, + filter_contender, + args.test[0].name, + ) + elif args.mode == "benchmarksfiltered": test_baseline = args.test_baseline[0].name test_contender = args.test_contender[0].name filter_baseline = args.filter_baseline[0] @@ -220,8 +266,12 @@ def main(): # NOTE: if test_baseline == test_contender and # filter_baseline == filter_contender, you are analyzing the stdev - description = 'Comparing %s (from %s) to %s (from %s)' % ( - filter_baseline, test_baseline, filter_contender, test_contender) + description = "Comparing %s (from %s) to %s (from %s)" % ( + filter_baseline, + test_baseline, + filter_contender, + test_contender, + ) else: # should never happen print("Unrecognized mode of operation: '%s'" % args.mode) @@ -231,199 +281,240 @@ def main(): check_inputs(test_baseline, test_contender, benchmark_options) if args.display_aggregates_only: - benchmark_options += ['--benchmark_display_aggregates_only=true'] + benchmark_options += ["--benchmark_display_aggregates_only=true"] options_baseline = [] options_contender = [] if filter_baseline and filter_contender: - options_baseline = ['--benchmark_filter=%s' % filter_baseline] - options_contender = ['--benchmark_filter=%s' % filter_contender] + options_baseline = ["--benchmark_filter=%s" % filter_baseline] + options_contender = ["--benchmark_filter=%s" % filter_contender] # Run the benchmarks and report the results - json1 = json1_orig = gbench.util.sort_benchmark_results(gbench.util.run_or_load_benchmark( - test_baseline, benchmark_options + options_baseline)) - json2 = json2_orig = gbench.util.sort_benchmark_results(gbench.util.run_or_load_benchmark( - test_contender, benchmark_options + options_contender)) + json1 = json1_orig = gbench.util.sort_benchmark_results( + gbench.util.run_or_load_benchmark( + test_baseline, benchmark_options + options_baseline + ) + ) + json2 = json2_orig = gbench.util.sort_benchmark_results( + gbench.util.run_or_load_benchmark( + test_contender, benchmark_options + options_contender + ) + ) # Now, filter the benchmarks so that the difference report can work if filter_baseline and filter_contender: - replacement = '[%s vs. %s]' % (filter_baseline, filter_contender) + replacement = "[%s vs. %s]" % (filter_baseline, filter_contender) json1 = gbench.report.filter_benchmark( - json1_orig, filter_baseline, replacement) + json1_orig, filter_baseline, replacement + ) json2 = gbench.report.filter_benchmark( - json2_orig, filter_contender, replacement) + json2_orig, filter_contender, replacement + ) - diff_report = gbench.report.get_difference_report( - json1, json2, args.utest) + diff_report = gbench.report.get_difference_report(json1, json2, args.utest) output_lines = gbench.report.print_difference_report( diff_report, args.display_aggregates_only, - args.utest, args.utest_alpha, args.color) + args.utest, + args.utest_alpha, + args.color, + ) print(description) for ln in output_lines: print(ln) # Optionally, diff and output to JSON if args.dump_to_json is not None: - with open(args.dump_to_json, 'w') as f_json: + with open(args.dump_to_json, "w") as f_json: json.dump(diff_report, f_json) + class TestParser(unittest.TestCase): def setUp(self): self.parser = create_parser() testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'gbench', - 'Inputs') - self.testInput0 = os.path.join(testInputs, 'test1_run1.json') - self.testInput1 = os.path.join(testInputs, 'test1_run2.json') + os.path.dirname(os.path.realpath(__file__)), "gbench", "Inputs" + ) + self.testInput0 = os.path.join(testInputs, "test1_run1.json") + self.testInput1 = os.path.join(testInputs, "test1_run2.json") def test_benchmarks_basic(self): parsed = self.parser.parse_args( - ['benchmarks', self.testInput0, self.testInput1]) + ["benchmarks", self.testInput0, self.testInput1] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.mode, "benchmarks") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) self.assertEqual(parsed.test_contender[0].name, self.testInput1) self.assertFalse(parsed.benchmark_options) def test_benchmarks_basic_without_utest(self): parsed = self.parser.parse_args( - ['--no-utest', 'benchmarks', self.testInput0, self.testInput1]) + ["--no-utest", "benchmarks", self.testInput0, self.testInput1] + ) self.assertFalse(parsed.display_aggregates_only) self.assertFalse(parsed.utest) self.assertEqual(parsed.utest_alpha, 0.05) - self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.mode, "benchmarks") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) self.assertEqual(parsed.test_contender[0].name, self.testInput1) self.assertFalse(parsed.benchmark_options) def test_benchmarks_basic_display_aggregates_only(self): parsed = self.parser.parse_args( - ['-a', 'benchmarks', self.testInput0, self.testInput1]) + ["-a", "benchmarks", self.testInput0, self.testInput1] + ) self.assertTrue(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.mode, "benchmarks") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) self.assertEqual(parsed.test_contender[0].name, self.testInput1) self.assertFalse(parsed.benchmark_options) def test_benchmarks_basic_with_utest_alpha(self): parsed = self.parser.parse_args( - ['--alpha=0.314', 'benchmarks', self.testInput0, self.testInput1]) + ["--alpha=0.314", "benchmarks", self.testInput0, self.testInput1] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) self.assertEqual(parsed.utest_alpha, 0.314) - self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.mode, "benchmarks") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) self.assertEqual(parsed.test_contender[0].name, self.testInput1) self.assertFalse(parsed.benchmark_options) def test_benchmarks_basic_without_utest_with_utest_alpha(self): parsed = self.parser.parse_args( - ['--no-utest', '--alpha=0.314', 'benchmarks', self.testInput0, self.testInput1]) + [ + "--no-utest", + "--alpha=0.314", + "benchmarks", + self.testInput0, + self.testInput1, + ] + ) self.assertFalse(parsed.display_aggregates_only) self.assertFalse(parsed.utest) self.assertEqual(parsed.utest_alpha, 0.314) - self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.mode, "benchmarks") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) self.assertEqual(parsed.test_contender[0].name, self.testInput1) self.assertFalse(parsed.benchmark_options) def test_benchmarks_with_remainder(self): parsed = self.parser.parse_args( - ['benchmarks', self.testInput0, self.testInput1, 'd']) + ["benchmarks", self.testInput0, self.testInput1, "d"] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.mode, "benchmarks") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) self.assertEqual(parsed.test_contender[0].name, self.testInput1) - self.assertEqual(parsed.benchmark_options, ['d']) + self.assertEqual(parsed.benchmark_options, ["d"]) def test_benchmarks_with_remainder_after_doubleminus(self): parsed = self.parser.parse_args( - ['benchmarks', self.testInput0, self.testInput1, '--', 'e']) + ["benchmarks", self.testInput0, self.testInput1, "--", "e"] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.mode, "benchmarks") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) self.assertEqual(parsed.test_contender[0].name, self.testInput1) - self.assertEqual(parsed.benchmark_options, ['e']) + self.assertEqual(parsed.benchmark_options, ["e"]) def test_filters_basic(self): - parsed = self.parser.parse_args( - ['filters', self.testInput0, 'c', 'd']) + parsed = self.parser.parse_args(["filters", self.testInput0, "c", "d"]) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'filters') + self.assertEqual(parsed.mode, "filters") self.assertEqual(parsed.test[0].name, self.testInput0) - self.assertEqual(parsed.filter_baseline[0], 'c') - self.assertEqual(parsed.filter_contender[0], 'd') + self.assertEqual(parsed.filter_baseline[0], "c") + self.assertEqual(parsed.filter_contender[0], "d") self.assertFalse(parsed.benchmark_options) def test_filters_with_remainder(self): parsed = self.parser.parse_args( - ['filters', self.testInput0, 'c', 'd', 'e']) + ["filters", self.testInput0, "c", "d", "e"] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'filters') + self.assertEqual(parsed.mode, "filters") self.assertEqual(parsed.test[0].name, self.testInput0) - self.assertEqual(parsed.filter_baseline[0], 'c') - self.assertEqual(parsed.filter_contender[0], 'd') - self.assertEqual(parsed.benchmark_options, ['e']) + self.assertEqual(parsed.filter_baseline[0], "c") + self.assertEqual(parsed.filter_contender[0], "d") + self.assertEqual(parsed.benchmark_options, ["e"]) def test_filters_with_remainder_after_doubleminus(self): parsed = self.parser.parse_args( - ['filters', self.testInput0, 'c', 'd', '--', 'f']) + ["filters", self.testInput0, "c", "d", "--", "f"] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'filters') + self.assertEqual(parsed.mode, "filters") self.assertEqual(parsed.test[0].name, self.testInput0) - self.assertEqual(parsed.filter_baseline[0], 'c') - self.assertEqual(parsed.filter_contender[0], 'd') - self.assertEqual(parsed.benchmark_options, ['f']) + self.assertEqual(parsed.filter_baseline[0], "c") + self.assertEqual(parsed.filter_contender[0], "d") + self.assertEqual(parsed.benchmark_options, ["f"]) def test_benchmarksfiltered_basic(self): parsed = self.parser.parse_args( - ['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e']) + ["benchmarksfiltered", self.testInput0, "c", self.testInput1, "e"] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'benchmarksfiltered') + self.assertEqual(parsed.mode, "benchmarksfiltered") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) - self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.filter_baseline[0], "c") self.assertEqual(parsed.test_contender[0].name, self.testInput1) - self.assertEqual(parsed.filter_contender[0], 'e') + self.assertEqual(parsed.filter_contender[0], "e") self.assertFalse(parsed.benchmark_options) def test_benchmarksfiltered_with_remainder(self): parsed = self.parser.parse_args( - ['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', 'f']) + [ + "benchmarksfiltered", + self.testInput0, + "c", + self.testInput1, + "e", + "f", + ] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'benchmarksfiltered') + self.assertEqual(parsed.mode, "benchmarksfiltered") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) - self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.filter_baseline[0], "c") self.assertEqual(parsed.test_contender[0].name, self.testInput1) - self.assertEqual(parsed.filter_contender[0], 'e') - self.assertEqual(parsed.benchmark_options[0], 'f') + self.assertEqual(parsed.filter_contender[0], "e") + self.assertEqual(parsed.benchmark_options[0], "f") def test_benchmarksfiltered_with_remainder_after_doubleminus(self): parsed = self.parser.parse_args( - ['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', '--', 'g']) + [ + "benchmarksfiltered", + self.testInput0, + "c", + self.testInput1, + "e", + "--", + "g", + ] + ) self.assertFalse(parsed.display_aggregates_only) self.assertTrue(parsed.utest) - self.assertEqual(parsed.mode, 'benchmarksfiltered') + self.assertEqual(parsed.mode, "benchmarksfiltered") self.assertEqual(parsed.test_baseline[0].name, self.testInput0) - self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.filter_baseline[0], "c") self.assertEqual(parsed.test_contender[0].name, self.testInput1) - self.assertEqual(parsed.filter_contender[0], 'e') - self.assertEqual(parsed.benchmark_options[0], 'g') + self.assertEqual(parsed.filter_contender[0], "e") + self.assertEqual(parsed.benchmark_options[0], "g") -if __name__ == '__main__': +if __name__ == "__main__": # unittest.main() main() diff --git a/tools/gbench/__init__.py b/tools/gbench/__init__.py index fce1a1acfb..9212568814 100644 --- a/tools/gbench/__init__.py +++ b/tools/gbench/__init__.py @@ -1,8 +1,8 @@ """Google Benchmark tooling""" -__author__ = 'Eric Fiselier' -__email__ = 'eric@efcs.ca' +__author__ = "Eric Fiselier" +__email__ = "eric@efcs.ca" __versioninfo__ = (0, 5, 0) -__version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' +__version__ = ".".join(str(v) for v in __versioninfo__) + "dev" -__all__ = [] +__all__ = [] # type: ignore diff --git a/tools/gbench/report.py b/tools/gbench/report.py index b2bbfb9f62..10e6b508f0 100644 --- a/tools/gbench/report.py +++ b/tools/gbench/report.py @@ -1,14 +1,17 @@ -"""report.py - Utilities for reporting statistics about benchmark results +# type: ignore + +""" +report.py - Utilities for reporting statistics about benchmark results """ -import unittest -import os -import re import copy +import os import random +import re +import unittest -from scipy.stats import mannwhitneyu, gmean from numpy import array +from scipy.stats import gmean, mannwhitneyu class BenchmarkColor(object): @@ -17,26 +20,25 @@ def __init__(self, name, code): self.code = code def __repr__(self): - return '%s%r' % (self.__class__.__name__, - (self.name, self.code)) + return "%s%r" % (self.__class__.__name__, (self.name, self.code)) def __format__(self, format): return self.code # Benchmark Colors Enumeration -BC_NONE = BenchmarkColor('NONE', '') -BC_MAGENTA = BenchmarkColor('MAGENTA', '\033[95m') -BC_CYAN = BenchmarkColor('CYAN', '\033[96m') -BC_OKBLUE = BenchmarkColor('OKBLUE', '\033[94m') -BC_OKGREEN = BenchmarkColor('OKGREEN', '\033[32m') -BC_HEADER = BenchmarkColor('HEADER', '\033[92m') -BC_WARNING = BenchmarkColor('WARNING', '\033[93m') -BC_WHITE = BenchmarkColor('WHITE', '\033[97m') -BC_FAIL = BenchmarkColor('FAIL', '\033[91m') -BC_ENDC = BenchmarkColor('ENDC', '\033[0m') -BC_BOLD = BenchmarkColor('BOLD', '\033[1m') -BC_UNDERLINE = BenchmarkColor('UNDERLINE', '\033[4m') +BC_NONE = BenchmarkColor("NONE", "") +BC_MAGENTA = BenchmarkColor("MAGENTA", "\033[95m") +BC_CYAN = BenchmarkColor("CYAN", "\033[96m") +BC_OKBLUE = BenchmarkColor("OKBLUE", "\033[94m") +BC_OKGREEN = BenchmarkColor("OKGREEN", "\033[32m") +BC_HEADER = BenchmarkColor("HEADER", "\033[92m") +BC_WARNING = BenchmarkColor("WARNING", "\033[93m") +BC_WHITE = BenchmarkColor("WHITE", "\033[97m") +BC_FAIL = BenchmarkColor("FAIL", "\033[91m") +BC_ENDC = BenchmarkColor("ENDC", "\033[0m") +BC_BOLD = BenchmarkColor("BOLD", "\033[1m") +BC_UNDERLINE = BenchmarkColor("UNDERLINE", "\033[4m") UTEST_MIN_REPETITIONS = 2 UTEST_OPTIMAL_REPETITIONS = 9 # Lowest reasonable number, More is better. @@ -59,10 +61,14 @@ def color_format(use_color, fmt_str, *args, **kwargs): """ assert use_color is True or use_color is False if not use_color: - args = [arg if not isinstance(arg, BenchmarkColor) else BC_NONE - for arg in args] - kwargs = {key: arg if not isinstance(arg, BenchmarkColor) else BC_NONE - for key, arg in kwargs.items()} + args = [ + arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for arg in args + ] + kwargs = { + key: arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for key, arg in kwargs.items() + } return fmt_str.format(*args, **kwargs) @@ -73,8 +79,8 @@ def find_longest_name(benchmark_list): """ longest_name = 1 for bc in benchmark_list: - if len(bc['name']) > longest_name: - longest_name = len(bc['name']) + if len(bc["name"]) > longest_name: + longest_name = len(bc["name"]) return longest_name @@ -95,13 +101,13 @@ def filter_benchmark(json_orig, family, replacement=""): """ regex = re.compile(family) filtered = {} - filtered['benchmarks'] = [] - for be in json_orig['benchmarks']: - if not regex.search(be['name']): + filtered["benchmarks"] = [] + for be in json_orig["benchmarks"]: + if not regex.search(be["name"]): continue filteredbench = copy.deepcopy(be) # Do NOT modify the old name! - filteredbench['name'] = regex.sub(replacement, filteredbench['name']) - filtered['benchmarks'].append(filteredbench) + filteredbench["name"] = regex.sub(replacement, filteredbench["name"]) + filtered["benchmarks"].append(filteredbench) return filtered @@ -110,9 +116,11 @@ def get_unique_benchmark_names(json): While *keeping* the order, give all the unique 'names' used for benchmarks. """ seen = set() - uniqued = [x['name'] for x in json['benchmarks'] - if x['name'] not in seen and - (seen.add(x['name']) or True)] + uniqued = [ + x["name"] + for x in json["benchmarks"] + if x["name"] not in seen and (seen.add(x["name"]) or True) + ] return uniqued @@ -125,7 +133,7 @@ def intersect(list1, list2): def is_potentially_comparable_benchmark(x): - return ('time_unit' in x and 'real_time' in x and 'cpu_time' in x) + return "time_unit" in x and "real_time" in x and "cpu_time" in x def partition_benchmarks(json1, json2): @@ -142,18 +150,24 @@ def partition_benchmarks(json1, json2): time_unit = None # Pick the time unit from the first entry of the lhs benchmark. # We should be careful not to crash with unexpected input. - for x in json1['benchmarks']: - if (x['name'] == name and is_potentially_comparable_benchmark(x)): - time_unit = x['time_unit'] + for x in json1["benchmarks"]: + if x["name"] == name and is_potentially_comparable_benchmark(x): + time_unit = x["time_unit"] break if time_unit is None: continue # Filter by name and time unit. # All the repetitions are assumed to be comparable. - lhs = [x for x in json1['benchmarks'] if x['name'] == name and - x['time_unit'] == time_unit] - rhs = [x for x in json2['benchmarks'] if x['name'] == name and - x['time_unit'] == time_unit] + lhs = [ + x + for x in json1["benchmarks"] + if x["name"] == name and x["time_unit"] == time_unit + ] + rhs = [ + x + for x in json2["benchmarks"] + if x["name"] == name and x["time_unit"] == time_unit + ] partitions.append([lhs, rhs]) return partitions @@ -164,7 +178,7 @@ def get_timedelta_field_as_seconds(benchmark, field_name): time_unit, as time in seconds. """ timedelta = benchmark[field_name] - time_unit = benchmark.get('time_unit', 's') + time_unit = benchmark.get("time_unit", "s") return timedelta * _TIME_UNIT_TO_SECONDS_MULTIPLIER.get(time_unit) @@ -174,11 +188,15 @@ def calculate_geomean(json): and calculate their geomean. """ times = [] - for benchmark in json['benchmarks']: - if 'run_type' in benchmark and benchmark['run_type'] == 'aggregate': + for benchmark in json["benchmarks"]: + if "run_type" in benchmark and benchmark["run_type"] == "aggregate": continue - times.append([get_timedelta_field_as_seconds(benchmark, 'real_time'), - get_timedelta_field_as_seconds(benchmark, 'cpu_time')]) + times.append( + [ + get_timedelta_field_as_seconds(benchmark, "real_time"), + get_timedelta_field_as_seconds(benchmark, "cpu_time"), + ] + ) return gmean(times) if times else array([]) @@ -190,19 +208,23 @@ def extract_field(partition, field_name): def calc_utest(timings_cpu, timings_time): - min_rep_cnt = min(len(timings_time[0]), - len(timings_time[1]), - len(timings_cpu[0]), - len(timings_cpu[1])) + min_rep_cnt = min( + len(timings_time[0]), + len(timings_time[1]), + len(timings_cpu[0]), + len(timings_cpu[1]), + ) # Does *everything* has at least UTEST_MIN_REPETITIONS repetitions? if min_rep_cnt < UTEST_MIN_REPETITIONS: return False, None, None time_pvalue = mannwhitneyu( - timings_time[0], timings_time[1], alternative='two-sided').pvalue + timings_time[0], timings_time[1], alternative="two-sided" + ).pvalue cpu_pvalue = mannwhitneyu( - timings_cpu[0], timings_cpu[1], alternative='two-sided').pvalue + timings_cpu[0], timings_cpu[1], alternative="two-sided" + ).pvalue return (min_rep_cnt >= UTEST_OPTIMAL_REPETITIONS), cpu_pvalue, time_pvalue @@ -212,38 +234,46 @@ def get_utest_color(pval): return BC_FAIL if pval >= utest_alpha else BC_OKGREEN # Check if we failed miserably with minimum required repetitions for utest - if not utest['have_optimal_repetitions'] and utest['cpu_pvalue'] is None and utest['time_pvalue'] is None: + if ( + not utest["have_optimal_repetitions"] + and utest["cpu_pvalue"] is None + and utest["time_pvalue"] is None + ): return [] dsc = "U Test, Repetitions: {} vs {}".format( - utest['nr_of_repetitions'], utest['nr_of_repetitions_other']) + utest["nr_of_repetitions"], utest["nr_of_repetitions_other"] + ) dsc_color = BC_OKGREEN # We still got some results to show but issue a warning about it. - if not utest['have_optimal_repetitions']: + if not utest["have_optimal_repetitions"]: dsc_color = BC_WARNING dsc += ". WARNING: Results unreliable! {}+ repetitions recommended.".format( - UTEST_OPTIMAL_REPETITIONS) + UTEST_OPTIMAL_REPETITIONS + ) special_str = "{}{:<{}s}{endc}{}{:16.4f}{endc}{}{:16.4f}{endc}{} {}" - return [color_format(use_color, - special_str, - BC_HEADER, - "{}{}".format(bc_name, UTEST_COL_NAME), - first_col_width, - get_utest_color( - utest['time_pvalue']), utest['time_pvalue'], - get_utest_color( - utest['cpu_pvalue']), utest['cpu_pvalue'], - dsc_color, dsc, - endc=BC_ENDC)] - - -def get_difference_report( - json1, - json2, - utest=False): + return [ + color_format( + use_color, + special_str, + BC_HEADER, + "{}{}".format(bc_name, UTEST_COL_NAME), + first_col_width, + get_utest_color(utest["time_pvalue"]), + utest["time_pvalue"], + get_utest_color(utest["cpu_pvalue"]), + utest["cpu_pvalue"], + dsc_color, + dsc, + endc=BC_ENDC, + ) + ] + + +def get_difference_report(json1, json2, utest=False): """ Calculate and report the difference between each test of two benchmarks runs specified as 'json1' and 'json2'. Output is another json containing @@ -254,37 +284,44 @@ def get_difference_report( diff_report = [] partitions = partition_benchmarks(json1, json2) for partition in partitions: - benchmark_name = partition[0][0]['name'] - label = partition[0][0]['label'] if 'label' in partition[0][0] else '' - time_unit = partition[0][0]['time_unit'] + benchmark_name = partition[0][0]["name"] + label = partition[0][0]["label"] if "label" in partition[0][0] else "" + time_unit = partition[0][0]["time_unit"] measurements = [] utest_results = {} # Careful, we may have different repetition count. for i in range(min(len(partition[0]), len(partition[1]))): bn = partition[0][i] other_bench = partition[1][i] - measurements.append({ - 'real_time': bn['real_time'], - 'cpu_time': bn['cpu_time'], - 'real_time_other': other_bench['real_time'], - 'cpu_time_other': other_bench['cpu_time'], - 'time': calculate_change(bn['real_time'], other_bench['real_time']), - 'cpu': calculate_change(bn['cpu_time'], other_bench['cpu_time']) - }) + measurements.append( + { + "real_time": bn["real_time"], + "cpu_time": bn["cpu_time"], + "real_time_other": other_bench["real_time"], + "cpu_time_other": other_bench["cpu_time"], + "time": calculate_change( + bn["real_time"], other_bench["real_time"] + ), + "cpu": calculate_change( + bn["cpu_time"], other_bench["cpu_time"] + ), + } + ) # After processing the whole partition, if requested, do the U test. if utest: - timings_cpu = extract_field(partition, 'cpu_time') - timings_time = extract_field(partition, 'real_time') + timings_cpu = extract_field(partition, "cpu_time") + timings_time = extract_field(partition, "real_time") have_optimal_repetitions, cpu_pvalue, time_pvalue = calc_utest( - timings_cpu, timings_time) + timings_cpu, timings_time + ) if cpu_pvalue and time_pvalue: utest_results = { - 'have_optimal_repetitions': have_optimal_repetitions, - 'cpu_pvalue': cpu_pvalue, - 'time_pvalue': time_pvalue, - 'nr_of_repetitions': len(timings_cpu[0]), - 'nr_of_repetitions_other': len(timings_cpu[1]) + "have_optimal_repetitions": have_optimal_repetitions, + "cpu_pvalue": cpu_pvalue, + "time_pvalue": time_pvalue, + "nr_of_repetitions": len(timings_cpu[0]), + "nr_of_repetitions_other": len(timings_cpu[1]), } # Store only if we had any measurements for given benchmark. @@ -292,47 +329,63 @@ def get_difference_report( # time units which are not compatible with other time units in the # benchmark suite. if measurements: - run_type = partition[0][0]['run_type'] if 'run_type' in partition[0][0] else '' - aggregate_name = partition[0][0]['aggregate_name'] if run_type == 'aggregate' and 'aggregate_name' in partition[0][0] else '' - diff_report.append({ - 'name': benchmark_name, - 'label': label, - 'measurements': measurements, - 'time_unit': time_unit, - 'run_type': run_type, - 'aggregate_name': aggregate_name, - 'utest': utest_results - }) + run_type = ( + partition[0][0]["run_type"] + if "run_type" in partition[0][0] + else "" + ) + aggregate_name = ( + partition[0][0]["aggregate_name"] + if run_type == "aggregate" + and "aggregate_name" in partition[0][0] + else "" + ) + diff_report.append( + { + "name": benchmark_name, + "label": label, + "measurements": measurements, + "time_unit": time_unit, + "run_type": run_type, + "aggregate_name": aggregate_name, + "utest": utest_results, + } + ) lhs_gmean = calculate_geomean(json1) rhs_gmean = calculate_geomean(json2) if lhs_gmean.any() and rhs_gmean.any(): - diff_report.append({ - 'name': 'OVERALL_GEOMEAN', - 'label': '', - 'measurements': [{ - 'real_time': lhs_gmean[0], - 'cpu_time': lhs_gmean[1], - 'real_time_other': rhs_gmean[0], - 'cpu_time_other': rhs_gmean[1], - 'time': calculate_change(lhs_gmean[0], rhs_gmean[0]), - 'cpu': calculate_change(lhs_gmean[1], rhs_gmean[1]) - }], - 'time_unit': 's', - 'run_type': 'aggregate', - 'aggregate_name': 'geomean', - 'utest': {} - }) + diff_report.append( + { + "name": "OVERALL_GEOMEAN", + "label": "", + "measurements": [ + { + "real_time": lhs_gmean[0], + "cpu_time": lhs_gmean[1], + "real_time_other": rhs_gmean[0], + "cpu_time_other": rhs_gmean[1], + "time": calculate_change(lhs_gmean[0], rhs_gmean[0]), + "cpu": calculate_change(lhs_gmean[1], rhs_gmean[1]), + } + ], + "time_unit": "s", + "run_type": "aggregate", + "aggregate_name": "geomean", + "utest": {}, + } + ) return diff_report def print_difference_report( - json_diff_report, - include_aggregates_only=False, - utest=False, - utest_alpha=0.05, - use_color=True): + json_diff_report, + include_aggregates_only=False, + utest=False, + utest_alpha=0.05, + use_color=True, +): """ Calculate and report the difference between each test of two benchmarks runs specified as 'json1' and 'json2'. @@ -348,44 +401,53 @@ def get_color(res): return BC_CYAN first_col_width = find_longest_name(json_diff_report) - first_col_width = max( - first_col_width, - len('Benchmark')) + first_col_width = max(first_col_width, len("Benchmark")) first_col_width += len(UTEST_COL_NAME) first_line = "{:<{}s}Time CPU Time Old Time New CPU Old CPU New".format( - 'Benchmark', 12 + first_col_width) - output_strs = [first_line, '-' * len(first_line)] + "Benchmark", 12 + first_col_width + ) + output_strs = [first_line, "-" * len(first_line)] fmt_str = "{}{:<{}s}{endc}{}{:+16.4f}{endc}{}{:+16.4f}{endc}{:14.0f}{:14.0f}{endc}{:14.0f}{:14.0f}" for benchmark in json_diff_report: # *If* we were asked to only include aggregates, # and if it is non-aggregate, then don't print it. - if not include_aggregates_only or not 'run_type' in benchmark or benchmark['run_type'] == 'aggregate': - for measurement in benchmark['measurements']: - output_strs += [color_format(use_color, - fmt_str, - BC_HEADER, - benchmark['name'], - first_col_width, - get_color(measurement['time']), - measurement['time'], - get_color(measurement['cpu']), - measurement['cpu'], - measurement['real_time'], - measurement['real_time_other'], - measurement['cpu_time'], - measurement['cpu_time_other'], - endc=BC_ENDC)] + if ( + not include_aggregates_only + or "run_type" not in benchmark + or benchmark["run_type"] == "aggregate" + ): + for measurement in benchmark["measurements"]: + output_strs += [ + color_format( + use_color, + fmt_str, + BC_HEADER, + benchmark["name"], + first_col_width, + get_color(measurement["time"]), + measurement["time"], + get_color(measurement["cpu"]), + measurement["cpu"], + measurement["real_time"], + measurement["real_time_other"], + measurement["cpu_time"], + measurement["cpu_time_other"], + endc=BC_ENDC, + ) + ] # After processing the measurements, if requested and # if applicable (e.g. u-test exists for given benchmark), # print the U test. - if utest and benchmark['utest']: - output_strs += print_utest(benchmark['name'], - benchmark['utest'], - utest_alpha=utest_alpha, - first_col_width=first_col_width, - use_color=use_color) + if utest and benchmark["utest"]: + output_strs += print_utest( + benchmark["name"], + benchmark["utest"], + utest_alpha=utest_alpha, + first_col_width=first_col_width, + use_color=use_color, + ) return output_strs @@ -397,21 +459,21 @@ def get_color(res): class TestGetUniqueBenchmarkNames(unittest.TestCase): def load_results(self): import json + testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'Inputs') - testOutput = os.path.join(testInputs, 'test3_run0.json') - with open(testOutput, 'r') as f: + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput = os.path.join(testInputs, "test3_run0.json") + with open(testOutput, "r") as f: json = json.load(f) return json def test_basic(self): expect_lines = [ - 'BM_One', - 'BM_Two', - 'short', # These two are not sorted - 'medium', # These two are not sorted + "BM_One", + "BM_Two", + "short", # These two are not sorted + "medium", # These two are not sorted ] json = self.load_results() output_lines = get_unique_benchmark_names(json) @@ -427,15 +489,15 @@ class TestReportDifference(unittest.TestCase): def setUpClass(cls): def load_results(): import json + testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'Inputs') - testOutput1 = os.path.join(testInputs, 'test1_run1.json') - testOutput2 = os.path.join(testInputs, 'test1_run2.json') - with open(testOutput1, 'r') as f: + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput1 = os.path.join(testInputs, "test1_run1.json") + testOutput2 = os.path.join(testInputs, "test1_run2.json") + with open(testOutput1, "r") as f: json1 = json.load(f) - with open(testOutput2, 'r') as f: + with open(testOutput2, "r") as f: json2 = json.load(f) return json1, json2 @@ -444,171 +506,323 @@ def load_results(): def test_json_diff_report_pretty_printing(self): expect_lines = [ - ['BM_SameTimes', '+0.0000', '+0.0000', '10', '10', '10', '10'], - ['BM_2xFaster', '-0.5000', '-0.5000', '50', '25', '50', '25'], - ['BM_2xSlower', '+1.0000', '+1.0000', '50', '100', '50', '100'], - ['BM_1PercentFaster', '-0.0100', '-0.0100', '100', '99', '100', '99'], - ['BM_1PercentSlower', '+0.0100', '+0.0100', '100', '101', '100', '101'], - ['BM_10PercentFaster', '-0.1000', '-0.1000', '100', '90', '100', '90'], - ['BM_10PercentSlower', '+0.1000', '+0.1000', '100', '110', '100', '110'], - ['BM_100xSlower', '+99.0000', '+99.0000', - '100', '10000', '100', '10000'], - ['BM_100xFaster', '-0.9900', '-0.9900', - '10000', '100', '10000', '100'], - ['BM_10PercentCPUToTime', '+0.1000', - '-0.1000', '100', '110', '100', '90'], - ['BM_ThirdFaster', '-0.3333', '-0.3334', '100', '67', '100', '67'], - ['BM_NotBadTimeUnit', '-0.9000', '+0.2000', '0', '0', '0', '1'], - ['BM_hasLabel', '+0.0000', '+0.0000', '1', '1', '1', '1'], - ['OVERALL_GEOMEAN', '-0.8113', '-0.7779', '0', '0', '0', '0'] + ["BM_SameTimes", "+0.0000", "+0.0000", "10", "10", "10", "10"], + ["BM_2xFaster", "-0.5000", "-0.5000", "50", "25", "50", "25"], + ["BM_2xSlower", "+1.0000", "+1.0000", "50", "100", "50", "100"], + [ + "BM_1PercentFaster", + "-0.0100", + "-0.0100", + "100", + "99", + "100", + "99", + ], + [ + "BM_1PercentSlower", + "+0.0100", + "+0.0100", + "100", + "101", + "100", + "101", + ], + [ + "BM_10PercentFaster", + "-0.1000", + "-0.1000", + "100", + "90", + "100", + "90", + ], + [ + "BM_10PercentSlower", + "+0.1000", + "+0.1000", + "100", + "110", + "100", + "110", + ], + [ + "BM_100xSlower", + "+99.0000", + "+99.0000", + "100", + "10000", + "100", + "10000", + ], + [ + "BM_100xFaster", + "-0.9900", + "-0.9900", + "10000", + "100", + "10000", + "100", + ], + [ + "BM_10PercentCPUToTime", + "+0.1000", + "-0.1000", + "100", + "110", + "100", + "90", + ], + ["BM_ThirdFaster", "-0.3333", "-0.3334", "100", "67", "100", "67"], + ["BM_NotBadTimeUnit", "-0.9000", "+0.2000", "0", "0", "0", "1"], + ["BM_hasLabel", "+0.0000", "+0.0000", "1", "1", "1", "1"], + ["OVERALL_GEOMEAN", "-0.8113", "-0.7779", "0", "0", "0", "0"], ] output_lines_with_header = print_difference_report( - self.json_diff_report, use_color=False) + self.json_diff_report, use_color=False + ) output_lines = output_lines_with_header[2:] print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(' ') if x] + parts = [x for x in output_lines[i].split(" ") if x] self.assertEqual(len(parts), 7) self.assertEqual(expect_lines[i], parts) def test_json_diff_report_output(self): expected_output = [ { - 'name': 'BM_SameTimes', - 'label': '', - 'measurements': [{'time': 0.0000, 'cpu': 0.0000, - 'real_time': 10, 'real_time_other': 10, - 'cpu_time': 10, 'cpu_time_other': 10}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_SameTimes", + "label": "", + "measurements": [ + { + "time": 0.0000, + "cpu": 0.0000, + "real_time": 10, + "real_time_other": 10, + "cpu_time": 10, + "cpu_time_other": 10, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_2xFaster', - 'label': '', - 'measurements': [{'time': -0.5000, 'cpu': -0.5000, - 'real_time': 50, 'real_time_other': 25, - 'cpu_time': 50, 'cpu_time_other': 25}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_2xFaster", + "label": "", + "measurements": [ + { + "time": -0.5000, + "cpu": -0.5000, + "real_time": 50, + "real_time_other": 25, + "cpu_time": 50, + "cpu_time_other": 25, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_2xSlower', - 'label': '', - 'measurements': [{'time': 1.0000, 'cpu': 1.0000, - 'real_time': 50, 'real_time_other': 100, - 'cpu_time': 50, 'cpu_time_other': 100}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_2xSlower", + "label": "", + "measurements": [ + { + "time": 1.0000, + "cpu": 1.0000, + "real_time": 50, + "real_time_other": 100, + "cpu_time": 50, + "cpu_time_other": 100, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_1PercentFaster', - 'label': '', - 'measurements': [{'time': -0.0100, 'cpu': -0.0100, - 'real_time': 100, 'real_time_other': 98.9999999, - 'cpu_time': 100, 'cpu_time_other': 98.9999999}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_1PercentFaster", + "label": "", + "measurements": [ + { + "time": -0.0100, + "cpu": -0.0100, + "real_time": 100, + "real_time_other": 98.9999999, + "cpu_time": 100, + "cpu_time_other": 98.9999999, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_1PercentSlower', - 'label': '', - 'measurements': [{'time': 0.0100, 'cpu': 0.0100, - 'real_time': 100, 'real_time_other': 101, - 'cpu_time': 100, 'cpu_time_other': 101}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_1PercentSlower", + "label": "", + "measurements": [ + { + "time": 0.0100, + "cpu": 0.0100, + "real_time": 100, + "real_time_other": 101, + "cpu_time": 100, + "cpu_time_other": 101, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_10PercentFaster', - 'label': '', - 'measurements': [{'time': -0.1000, 'cpu': -0.1000, - 'real_time': 100, 'real_time_other': 90, - 'cpu_time': 100, 'cpu_time_other': 90}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_10PercentFaster", + "label": "", + "measurements": [ + { + "time": -0.1000, + "cpu": -0.1000, + "real_time": 100, + "real_time_other": 90, + "cpu_time": 100, + "cpu_time_other": 90, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_10PercentSlower', - 'label': '', - 'measurements': [{'time': 0.1000, 'cpu': 0.1000, - 'real_time': 100, 'real_time_other': 110, - 'cpu_time': 100, 'cpu_time_other': 110}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_10PercentSlower", + "label": "", + "measurements": [ + { + "time": 0.1000, + "cpu": 0.1000, + "real_time": 100, + "real_time_other": 110, + "cpu_time": 100, + "cpu_time_other": 110, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_100xSlower', - 'label': '', - 'measurements': [{'time': 99.0000, 'cpu': 99.0000, - 'real_time': 100, 'real_time_other': 10000, - 'cpu_time': 100, 'cpu_time_other': 10000}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_100xSlower", + "label": "", + "measurements": [ + { + "time": 99.0000, + "cpu": 99.0000, + "real_time": 100, + "real_time_other": 10000, + "cpu_time": 100, + "cpu_time_other": 10000, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_100xFaster', - 'label': '', - 'measurements': [{'time': -0.9900, 'cpu': -0.9900, - 'real_time': 10000, 'real_time_other': 100, - 'cpu_time': 10000, 'cpu_time_other': 100}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_100xFaster", + "label": "", + "measurements": [ + { + "time": -0.9900, + "cpu": -0.9900, + "real_time": 10000, + "real_time_other": 100, + "cpu_time": 10000, + "cpu_time_other": 100, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_10PercentCPUToTime', - 'label': '', - 'measurements': [{'time': 0.1000, 'cpu': -0.1000, - 'real_time': 100, 'real_time_other': 110, - 'cpu_time': 100, 'cpu_time_other': 90}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_10PercentCPUToTime", + "label": "", + "measurements": [ + { + "time": 0.1000, + "cpu": -0.1000, + "real_time": 100, + "real_time_other": 110, + "cpu_time": 100, + "cpu_time_other": 90, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_ThirdFaster', - 'label': '', - 'measurements': [{'time': -0.3333, 'cpu': -0.3334, - 'real_time': 100, 'real_time_other': 67, - 'cpu_time': 100, 'cpu_time_other': 67}], - 'time_unit': 'ns', - 'utest': {} + "name": "BM_ThirdFaster", + "label": "", + "measurements": [ + { + "time": -0.3333, + "cpu": -0.3334, + "real_time": 100, + "real_time_other": 67, + "cpu_time": 100, + "cpu_time_other": 67, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'BM_NotBadTimeUnit', - 'label': '', - 'measurements': [{'time': -0.9000, 'cpu': 0.2000, - 'real_time': 0.4, 'real_time_other': 0.04, - 'cpu_time': 0.5, 'cpu_time_other': 0.6}], - 'time_unit': 's', - 'utest': {} + "name": "BM_NotBadTimeUnit", + "label": "", + "measurements": [ + { + "time": -0.9000, + "cpu": 0.2000, + "real_time": 0.4, + "real_time_other": 0.04, + "cpu_time": 0.5, + "cpu_time_other": 0.6, + } + ], + "time_unit": "s", + "utest": {}, }, { - 'name': 'BM_hasLabel', - 'label': 'a label', - 'measurements': [{'time': 0.0000, 'cpu': 0.0000, - 'real_time': 1, 'real_time_other': 1, - 'cpu_time': 1, 'cpu_time_other': 1}], - 'time_unit': 's', - 'utest': {} + "name": "BM_hasLabel", + "label": "a label", + "measurements": [ + { + "time": 0.0000, + "cpu": 0.0000, + "real_time": 1, + "real_time_other": 1, + "cpu_time": 1, + "cpu_time_other": 1, + } + ], + "time_unit": "s", + "utest": {}, }, { - 'name': 'OVERALL_GEOMEAN', - 'label': '', - 'measurements': [{'real_time': 3.1622776601683826e-06, 'cpu_time': 3.2130844755623912e-06, - 'real_time_other': 1.9768988699420897e-07, 'cpu_time_other': 2.397447755209533e-07, - 'time': -0.8112976497120911, 'cpu': -0.7778551721181174}], - 'time_unit': 's', - 'run_type': 'aggregate', - 'aggregate_name': 'geomean', 'utest': {} + "name": "OVERALL_GEOMEAN", + "label": "", + "measurements": [ + { + "real_time": 3.1622776601683826e-06, + "cpu_time": 3.2130844755623912e-06, + "real_time_other": 1.9768988699420897e-07, + "cpu_time_other": 2.397447755209533e-07, + "time": -0.8112976497120911, + "cpu": -0.7778551721181174, + } + ], + "time_unit": "s", + "run_type": "aggregate", + "aggregate_name": "geomean", + "utest": {}, }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip( - self.json_diff_report, expected_output): - self.assertEqual(out['name'], expected['name']) - self.assertEqual(out['label'], expected['label']) - self.assertEqual(out['time_unit'], expected['time_unit']) + for out, expected in zip(self.json_diff_report, expected_output): + self.assertEqual(out["name"], expected["name"]) + self.assertEqual(out["label"], expected["label"]) + self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) assert_measurements(self, out, expected) @@ -618,12 +832,12 @@ class TestReportDifferenceBetweenFamilies(unittest.TestCase): def setUpClass(cls): def load_result(): import json + testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'Inputs') - testOutput = os.path.join(testInputs, 'test2_run.json') - with open(testOutput, 'r') as f: + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput = os.path.join(testInputs, "test2_run.json") + with open(testOutput, "r") as f: json = json.load(f) return json @@ -634,65 +848,108 @@ def load_result(): def test_json_diff_report_pretty_printing(self): expect_lines = [ - ['.', '-0.5000', '-0.5000', '10', '5', '10', '5'], - ['./4', '-0.5000', '-0.5000', '40', '20', '40', '20'], - ['Prefix/.', '-0.5000', '-0.5000', '20', '10', '20', '10'], - ['Prefix/./3', '-0.5000', '-0.5000', '30', '15', '30', '15'], - ['OVERALL_GEOMEAN', '-0.5000', '-0.5000', '0', '0', '0', '0'] + [".", "-0.5000", "-0.5000", "10", "5", "10", "5"], + ["./4", "-0.5000", "-0.5000", "40", "20", "40", "20"], + ["Prefix/.", "-0.5000", "-0.5000", "20", "10", "20", "10"], + ["Prefix/./3", "-0.5000", "-0.5000", "30", "15", "30", "15"], + ["OVERALL_GEOMEAN", "-0.5000", "-0.5000", "0", "0", "0", "0"], ] output_lines_with_header = print_difference_report( - self.json_diff_report, use_color=False) + self.json_diff_report, use_color=False + ) output_lines = output_lines_with_header[2:] print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(' ') if x] + parts = [x for x in output_lines[i].split(" ") if x] self.assertEqual(len(parts), 7) self.assertEqual(expect_lines[i], parts) def test_json_diff_report(self): expected_output = [ { - 'name': u'.', - 'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 10, 'real_time_other': 5, 'cpu_time': 10, 'cpu_time_other': 5}], - 'time_unit': 'ns', - 'utest': {} + "name": ".", + "measurements": [ + { + "time": -0.5, + "cpu": -0.5, + "real_time": 10, + "real_time_other": 5, + "cpu_time": 10, + "cpu_time_other": 5, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': u'./4', - 'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 40, 'real_time_other': 20, 'cpu_time': 40, 'cpu_time_other': 20}], - 'time_unit': 'ns', - 'utest': {}, + "name": "./4", + "measurements": [ + { + "time": -0.5, + "cpu": -0.5, + "real_time": 40, + "real_time_other": 20, + "cpu_time": 40, + "cpu_time_other": 20, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': u'Prefix/.', - 'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 20, 'real_time_other': 10, 'cpu_time': 20, 'cpu_time_other': 10}], - 'time_unit': 'ns', - 'utest': {} + "name": "Prefix/.", + "measurements": [ + { + "time": -0.5, + "cpu": -0.5, + "real_time": 20, + "real_time_other": 10, + "cpu_time": 20, + "cpu_time_other": 10, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': u'Prefix/./3', - 'measurements': [{'time': -0.5, 'cpu': -0.5, 'real_time': 30, 'real_time_other': 15, 'cpu_time': 30, 'cpu_time_other': 15}], - 'time_unit': 'ns', - 'utest': {} + "name": "Prefix/./3", + "measurements": [ + { + "time": -0.5, + "cpu": -0.5, + "real_time": 30, + "real_time_other": 15, + "cpu_time": 30, + "cpu_time_other": 15, + } + ], + "time_unit": "ns", + "utest": {}, }, { - 'name': 'OVERALL_GEOMEAN', - 'measurements': [{'real_time': 2.213363839400641e-08, 'cpu_time': 2.213363839400641e-08, - 'real_time_other': 1.1066819197003185e-08, 'cpu_time_other': 1.1066819197003185e-08, - 'time': -0.5000000000000009, 'cpu': -0.5000000000000009}], - 'time_unit': 's', - 'run_type': 'aggregate', - 'aggregate_name': 'geomean', - 'utest': {} - } + "name": "OVERALL_GEOMEAN", + "measurements": [ + { + "real_time": 2.213363839400641e-08, + "cpu_time": 2.213363839400641e-08, + "real_time_other": 1.1066819197003185e-08, + "cpu_time_other": 1.1066819197003185e-08, + "time": -0.5000000000000009, + "cpu": -0.5000000000000009, + } + ], + "time_unit": "s", + "run_type": "aggregate", + "aggregate_name": "geomean", + "utest": {}, + }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip( - self.json_diff_report, expected_output): - self.assertEqual(out['name'], expected['name']) - self.assertEqual(out['time_unit'], expected['time_unit']) + for out, expected in zip(self.json_diff_report, expected_output): + self.assertEqual(out["name"], expected["name"]) + self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) assert_measurements(self, out, expected) @@ -702,424 +959,489 @@ class TestReportDifferenceWithUTest(unittest.TestCase): def setUpClass(cls): def load_results(): import json + testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'Inputs') - testOutput1 = os.path.join(testInputs, 'test3_run0.json') - testOutput2 = os.path.join(testInputs, 'test3_run1.json') - with open(testOutput1, 'r') as f: + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput1 = os.path.join(testInputs, "test3_run0.json") + testOutput2 = os.path.join(testInputs, "test3_run1.json") + with open(testOutput1, "r") as f: json1 = json.load(f) - with open(testOutput2, 'r') as f: + with open(testOutput2, "r") as f: json2 = json.load(f) return json1, json2 json1, json2 = load_results() - cls.json_diff_report = get_difference_report( - json1, json2, utest=True) + cls.json_diff_report = get_difference_report(json1, json2, utest=True) def test_json_diff_report_pretty_printing(self): expect_lines = [ - ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'], - ['BM_Two', '+0.1111', '-0.0111', '9', '10', '90', '89'], - ['BM_Two', '-0.1250', '-0.1628', '8', '7', '86', '72'], - ['BM_Two_pvalue', - '1.0000', - '0.6667', - 'U', - 'Test,', - 'Repetitions:', - '2', - 'vs', - '2.', - 'WARNING:', - 'Results', - 'unreliable!', - '9+', - 'repetitions', - 'recommended.'], - ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'], - ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'], - ['short_pvalue', - '0.7671', - '0.2000', - 'U', - 'Test,', - 'Repetitions:', - '2', - 'vs', - '3.', - 'WARNING:', - 'Results', - 'unreliable!', - '9+', - 'repetitions', - 'recommended.'], - ['medium', '-0.3750', '-0.3375', '8', '5', '80', '53'], - ['OVERALL_GEOMEAN', '+1.6405', '-0.6985', '0', '0', '0', '0'] + ["BM_One", "-0.1000", "+0.1000", "10", "9", "100", "110"], + ["BM_Two", "+0.1111", "-0.0111", "9", "10", "90", "89"], + ["BM_Two", "-0.1250", "-0.1628", "8", "7", "86", "72"], + [ + "BM_Two_pvalue", + "1.0000", + "0.6667", + "U", + "Test,", + "Repetitions:", + "2", + "vs", + "2.", + "WARNING:", + "Results", + "unreliable!", + "9+", + "repetitions", + "recommended.", + ], + ["short", "-0.1250", "-0.0625", "8", "7", "80", "75"], + ["short", "-0.4325", "-0.1351", "8", "5", "77", "67"], + [ + "short_pvalue", + "0.7671", + "0.2000", + "U", + "Test,", + "Repetitions:", + "2", + "vs", + "3.", + "WARNING:", + "Results", + "unreliable!", + "9+", + "repetitions", + "recommended.", + ], + ["medium", "-0.3750", "-0.3375", "8", "5", "80", "53"], + ["OVERALL_GEOMEAN", "+1.6405", "-0.6985", "0", "0", "0", "0"], ] output_lines_with_header = print_difference_report( - self.json_diff_report, utest=True, utest_alpha=0.05, use_color=False) + self.json_diff_report, utest=True, utest_alpha=0.05, use_color=False + ) output_lines = output_lines_with_header[2:] print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(' ') if x] + parts = [x for x in output_lines[i].split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report_pretty_printing_aggregates_only(self): expect_lines = [ - ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'], - ['BM_Two_pvalue', - '1.0000', - '0.6667', - 'U', - 'Test,', - 'Repetitions:', - '2', - 'vs', - '2.', - 'WARNING:', - 'Results', - 'unreliable!', - '9+', - 'repetitions', - 'recommended.'], - ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'], - ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'], - ['short_pvalue', - '0.7671', - '0.2000', - 'U', - 'Test,', - 'Repetitions:', - '2', - 'vs', - '3.', - 'WARNING:', - 'Results', - 'unreliable!', - '9+', - 'repetitions', - 'recommended.'], - ['OVERALL_GEOMEAN', '+1.6405', '-0.6985', '0', '0', '0', '0'] + ["BM_One", "-0.1000", "+0.1000", "10", "9", "100", "110"], + [ + "BM_Two_pvalue", + "1.0000", + "0.6667", + "U", + "Test,", + "Repetitions:", + "2", + "vs", + "2.", + "WARNING:", + "Results", + "unreliable!", + "9+", + "repetitions", + "recommended.", + ], + ["short", "-0.1250", "-0.0625", "8", "7", "80", "75"], + ["short", "-0.4325", "-0.1351", "8", "5", "77", "67"], + [ + "short_pvalue", + "0.7671", + "0.2000", + "U", + "Test,", + "Repetitions:", + "2", + "vs", + "3.", + "WARNING:", + "Results", + "unreliable!", + "9+", + "repetitions", + "recommended.", + ], + ["OVERALL_GEOMEAN", "+1.6405", "-0.6985", "0", "0", "0", "0"], ] output_lines_with_header = print_difference_report( - self.json_diff_report, include_aggregates_only=True, utest=True, utest_alpha=0.05, use_color=False) + self.json_diff_report, + include_aggregates_only=True, + utest=True, + utest_alpha=0.05, + use_color=False, + ) output_lines = output_lines_with_header[2:] print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(' ') if x] + parts = [x for x in output_lines[i].split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report(self): expected_output = [ { - 'name': u'BM_One', - 'measurements': [ - {'time': -0.1, - 'cpu': 0.1, - 'real_time': 10, - 'real_time_other': 9, - 'cpu_time': 100, - 'cpu_time_other': 110} + "name": "BM_One", + "measurements": [ + { + "time": -0.1, + "cpu": 0.1, + "real_time": 10, + "real_time_other": 9, + "cpu_time": 100, + "cpu_time_other": 110, + } ], - 'time_unit': 'ns', - 'utest': {} + "time_unit": "ns", + "utest": {}, }, { - 'name': u'BM_Two', - 'measurements': [ - {'time': 0.1111111111111111, - 'cpu': -0.011111111111111112, - 'real_time': 9, - 'real_time_other': 10, - 'cpu_time': 90, - 'cpu_time_other': 89}, - {'time': -0.125, 'cpu': -0.16279069767441862, 'real_time': 8, - 'real_time_other': 7, 'cpu_time': 86, 'cpu_time_other': 72} + "name": "BM_Two", + "measurements": [ + { + "time": 0.1111111111111111, + "cpu": -0.011111111111111112, + "real_time": 9, + "real_time_other": 10, + "cpu_time": 90, + "cpu_time_other": 89, + }, + { + "time": -0.125, + "cpu": -0.16279069767441862, + "real_time": 8, + "real_time_other": 7, + "cpu_time": 86, + "cpu_time_other": 72, + }, ], - 'time_unit': 'ns', - 'utest': { - 'have_optimal_repetitions': False, 'cpu_pvalue': 0.6666666666666666, 'time_pvalue': 1.0 - } + "time_unit": "ns", + "utest": { + "have_optimal_repetitions": False, + "cpu_pvalue": 0.6666666666666666, + "time_pvalue": 1.0, + }, }, { - 'name': u'short', - 'measurements': [ - {'time': -0.125, - 'cpu': -0.0625, - 'real_time': 8, - 'real_time_other': 7, - 'cpu_time': 80, - 'cpu_time_other': 75}, - {'time': -0.4325, - 'cpu': -0.13506493506493514, - 'real_time': 8, - 'real_time_other': 4.54, - 'cpu_time': 77, - 'cpu_time_other': 66.6} + "name": "short", + "measurements": [ + { + "time": -0.125, + "cpu": -0.0625, + "real_time": 8, + "real_time_other": 7, + "cpu_time": 80, + "cpu_time_other": 75, + }, + { + "time": -0.4325, + "cpu": -0.13506493506493514, + "real_time": 8, + "real_time_other": 4.54, + "cpu_time": 77, + "cpu_time_other": 66.6, + }, ], - 'time_unit': 'ns', - 'utest': { - 'have_optimal_repetitions': False, 'cpu_pvalue': 0.2, 'time_pvalue': 0.7670968684102772 - } + "time_unit": "ns", + "utest": { + "have_optimal_repetitions": False, + "cpu_pvalue": 0.2, + "time_pvalue": 0.7670968684102772, + }, }, { - 'name': u'medium', - 'measurements': [ - {'time': -0.375, - 'cpu': -0.3375, - 'real_time': 8, - 'real_time_other': 5, - 'cpu_time': 80, - 'cpu_time_other': 53} + "name": "medium", + "measurements": [ + { + "time": -0.375, + "cpu": -0.3375, + "real_time": 8, + "real_time_other": 5, + "cpu_time": 80, + "cpu_time_other": 53, + } ], - 'time_unit': 'ns', - 'utest': {} + "time_unit": "ns", + "utest": {}, }, { - 'name': 'OVERALL_GEOMEAN', - 'measurements': [{'real_time': 8.48528137423858e-09, 'cpu_time': 8.441336246629233e-08, - 'real_time_other': 2.2405267593145244e-08, 'cpu_time_other': 2.5453661413660466e-08, - 'time': 1.6404861082353634, 'cpu': -0.6984640740519662}], - 'time_unit': 's', - 'run_type': 'aggregate', - 'aggregate_name': 'geomean', - 'utest': {} - } + "name": "OVERALL_GEOMEAN", + "measurements": [ + { + "real_time": 8.48528137423858e-09, + "cpu_time": 8.441336246629233e-08, + "real_time_other": 2.2405267593145244e-08, + "cpu_time_other": 2.5453661413660466e-08, + "time": 1.6404861082353634, + "cpu": -0.6984640740519662, + } + ], + "time_unit": "s", + "run_type": "aggregate", + "aggregate_name": "geomean", + "utest": {}, + }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip( - self.json_diff_report, expected_output): - self.assertEqual(out['name'], expected['name']) - self.assertEqual(out['time_unit'], expected['time_unit']) + for out, expected in zip(self.json_diff_report, expected_output): + self.assertEqual(out["name"], expected["name"]) + self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) assert_measurements(self, out, expected) class TestReportDifferenceWithUTestWhileDisplayingAggregatesOnly( - unittest.TestCase): + unittest.TestCase +): @classmethod def setUpClass(cls): def load_results(): import json + testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'Inputs') - testOutput1 = os.path.join(testInputs, 'test3_run0.json') - testOutput2 = os.path.join(testInputs, 'test3_run1.json') - with open(testOutput1, 'r') as f: + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput1 = os.path.join(testInputs, "test3_run0.json") + testOutput2 = os.path.join(testInputs, "test3_run1.json") + with open(testOutput1, "r") as f: json1 = json.load(f) - with open(testOutput2, 'r') as f: + with open(testOutput2, "r") as f: json2 = json.load(f) return json1, json2 json1, json2 = load_results() - cls.json_diff_report = get_difference_report( - json1, json2, utest=True) + cls.json_diff_report = get_difference_report(json1, json2, utest=True) def test_json_diff_report_pretty_printing(self): expect_lines = [ - ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'], - ['BM_Two', '+0.1111', '-0.0111', '9', '10', '90', '89'], - ['BM_Two', '-0.1250', '-0.1628', '8', '7', '86', '72'], - ['BM_Two_pvalue', - '1.0000', - '0.6667', - 'U', - 'Test,', - 'Repetitions:', - '2', - 'vs', - '2.', - 'WARNING:', - 'Results', - 'unreliable!', - '9+', - 'repetitions', - 'recommended.'], - ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'], - ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'], - ['short_pvalue', - '0.7671', - '0.2000', - 'U', - 'Test,', - 'Repetitions:', - '2', - 'vs', - '3.', - 'WARNING:', - 'Results', - 'unreliable!', - '9+', - 'repetitions', - 'recommended.'], - ['medium', '-0.3750', '-0.3375', '8', '5', '80', '53'], - ['OVERALL_GEOMEAN', '+1.6405', '-0.6985', '0', '0', '0', '0'] + ["BM_One", "-0.1000", "+0.1000", "10", "9", "100", "110"], + ["BM_Two", "+0.1111", "-0.0111", "9", "10", "90", "89"], + ["BM_Two", "-0.1250", "-0.1628", "8", "7", "86", "72"], + [ + "BM_Two_pvalue", + "1.0000", + "0.6667", + "U", + "Test,", + "Repetitions:", + "2", + "vs", + "2.", + "WARNING:", + "Results", + "unreliable!", + "9+", + "repetitions", + "recommended.", + ], + ["short", "-0.1250", "-0.0625", "8", "7", "80", "75"], + ["short", "-0.4325", "-0.1351", "8", "5", "77", "67"], + [ + "short_pvalue", + "0.7671", + "0.2000", + "U", + "Test,", + "Repetitions:", + "2", + "vs", + "3.", + "WARNING:", + "Results", + "unreliable!", + "9+", + "repetitions", + "recommended.", + ], + ["medium", "-0.3750", "-0.3375", "8", "5", "80", "53"], + ["OVERALL_GEOMEAN", "+1.6405", "-0.6985", "0", "0", "0", "0"], ] output_lines_with_header = print_difference_report( - self.json_diff_report, - utest=True, utest_alpha=0.05, use_color=False) + self.json_diff_report, utest=True, utest_alpha=0.05, use_color=False + ) output_lines = output_lines_with_header[2:] print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(' ') if x] + parts = [x for x in output_lines[i].split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report(self): expected_output = [ { - 'name': u'BM_One', - 'measurements': [ - {'time': -0.1, - 'cpu': 0.1, - 'real_time': 10, - 'real_time_other': 9, - 'cpu_time': 100, - 'cpu_time_other': 110} + "name": "BM_One", + "measurements": [ + { + "time": -0.1, + "cpu": 0.1, + "real_time": 10, + "real_time_other": 9, + "cpu_time": 100, + "cpu_time_other": 110, + } ], - 'time_unit': 'ns', - 'utest': {} + "time_unit": "ns", + "utest": {}, }, { - 'name': u'BM_Two', - 'measurements': [ - {'time': 0.1111111111111111, - 'cpu': -0.011111111111111112, - 'real_time': 9, - 'real_time_other': 10, - 'cpu_time': 90, - 'cpu_time_other': 89}, - {'time': -0.125, 'cpu': -0.16279069767441862, 'real_time': 8, - 'real_time_other': 7, 'cpu_time': 86, 'cpu_time_other': 72} + "name": "BM_Two", + "measurements": [ + { + "time": 0.1111111111111111, + "cpu": -0.011111111111111112, + "real_time": 9, + "real_time_other": 10, + "cpu_time": 90, + "cpu_time_other": 89, + }, + { + "time": -0.125, + "cpu": -0.16279069767441862, + "real_time": 8, + "real_time_other": 7, + "cpu_time": 86, + "cpu_time_other": 72, + }, ], - 'time_unit': 'ns', - 'utest': { - 'have_optimal_repetitions': False, 'cpu_pvalue': 0.6666666666666666, 'time_pvalue': 1.0 - } + "time_unit": "ns", + "utest": { + "have_optimal_repetitions": False, + "cpu_pvalue": 0.6666666666666666, + "time_pvalue": 1.0, + }, }, { - 'name': u'short', - 'measurements': [ - {'time': -0.125, - 'cpu': -0.0625, - 'real_time': 8, - 'real_time_other': 7, - 'cpu_time': 80, - 'cpu_time_other': 75}, - {'time': -0.4325, - 'cpu': -0.13506493506493514, - 'real_time': 8, - 'real_time_other': 4.54, - 'cpu_time': 77, - 'cpu_time_other': 66.6} + "name": "short", + "measurements": [ + { + "time": -0.125, + "cpu": -0.0625, + "real_time": 8, + "real_time_other": 7, + "cpu_time": 80, + "cpu_time_other": 75, + }, + { + "time": -0.4325, + "cpu": -0.13506493506493514, + "real_time": 8, + "real_time_other": 4.54, + "cpu_time": 77, + "cpu_time_other": 66.6, + }, ], - 'time_unit': 'ns', - 'utest': { - 'have_optimal_repetitions': False, 'cpu_pvalue': 0.2, 'time_pvalue': 0.7670968684102772 - } + "time_unit": "ns", + "utest": { + "have_optimal_repetitions": False, + "cpu_pvalue": 0.2, + "time_pvalue": 0.7670968684102772, + }, }, { - 'name': u'medium', - 'measurements': [ - {'real_time_other': 5, - 'cpu_time': 80, - 'time': -0.375, - 'real_time': 8, - 'cpu_time_other': 53, - 'cpu': -0.3375 - } + "name": "medium", + "measurements": [ + { + "real_time_other": 5, + "cpu_time": 80, + "time": -0.375, + "real_time": 8, + "cpu_time_other": 53, + "cpu": -0.3375, + } ], - 'utest': {}, - 'time_unit': u'ns', - 'aggregate_name': '' + "utest": {}, + "time_unit": "ns", + "aggregate_name": "", }, { - 'name': 'OVERALL_GEOMEAN', - 'measurements': [{'real_time': 8.48528137423858e-09, 'cpu_time': 8.441336246629233e-08, - 'real_time_other': 2.2405267593145244e-08, 'cpu_time_other': 2.5453661413660466e-08, - 'time': 1.6404861082353634, 'cpu': -0.6984640740519662}], - 'time_unit': 's', - 'run_type': 'aggregate', - 'aggregate_name': 'geomean', - 'utest': {} - } + "name": "OVERALL_GEOMEAN", + "measurements": [ + { + "real_time": 8.48528137423858e-09, + "cpu_time": 8.441336246629233e-08, + "real_time_other": 2.2405267593145244e-08, + "cpu_time_other": 2.5453661413660466e-08, + "time": 1.6404861082353634, + "cpu": -0.6984640740519662, + } + ], + "time_unit": "s", + "run_type": "aggregate", + "aggregate_name": "geomean", + "utest": {}, + }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip( - self.json_diff_report, expected_output): - self.assertEqual(out['name'], expected['name']) - self.assertEqual(out['time_unit'], expected['time_unit']) + for out, expected in zip(self.json_diff_report, expected_output): + self.assertEqual(out["name"], expected["name"]) + self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) assert_measurements(self, out, expected) -class TestReportDifferenceForPercentageAggregates( - unittest.TestCase): +class TestReportDifferenceForPercentageAggregates(unittest.TestCase): @classmethod def setUpClass(cls): def load_results(): import json + testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'Inputs') - testOutput1 = os.path.join(testInputs, 'test4_run0.json') - testOutput2 = os.path.join(testInputs, 'test4_run1.json') - with open(testOutput1, 'r') as f: + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput1 = os.path.join(testInputs, "test4_run0.json") + testOutput2 = os.path.join(testInputs, "test4_run1.json") + with open(testOutput1, "r") as f: json1 = json.load(f) - with open(testOutput2, 'r') as f: + with open(testOutput2, "r") as f: json2 = json.load(f) return json1, json2 json1, json2 = load_results() - cls.json_diff_report = get_difference_report( - json1, json2, utest=True) + cls.json_diff_report = get_difference_report(json1, json2, utest=True) def test_json_diff_report_pretty_printing(self): - expect_lines = [ - ['whocares', '-0.5000', '+0.5000', '0', '0', '0', '0'] - ] + expect_lines = [["whocares", "-0.5000", "+0.5000", "0", "0", "0", "0"]] output_lines_with_header = print_difference_report( - self.json_diff_report, - utest=True, utest_alpha=0.05, use_color=False) + self.json_diff_report, utest=True, utest_alpha=0.05, use_color=False + ) output_lines = output_lines_with_header[2:] print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(' ') if x] + parts = [x for x in output_lines[i].split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report(self): expected_output = [ { - 'name': u'whocares', - 'measurements': [ - {'time': -0.5, - 'cpu': 0.5, - 'real_time': 0.01, - 'real_time_other': 0.005, - 'cpu_time': 0.10, - 'cpu_time_other': 0.15} + "name": "whocares", + "measurements": [ + { + "time": -0.5, + "cpu": 0.5, + "real_time": 0.01, + "real_time_other": 0.005, + "cpu_time": 0.10, + "cpu_time_other": 0.15, + } ], - 'time_unit': 'ns', - 'utest': {} + "time_unit": "ns", + "utest": {}, } ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip( - self.json_diff_report, expected_output): - self.assertEqual(out['name'], expected['name']) - self.assertEqual(out['time_unit'], expected['time_unit']) + for out, expected in zip(self.json_diff_report, expected_output): + self.assertEqual(out["name"], expected["name"]) + self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) assert_measurements(self, out, expected) @@ -1129,12 +1451,12 @@ class TestReportSorting(unittest.TestCase): def setUpClass(cls): def load_result(): import json + testInputs = os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'Inputs') - testOutput = os.path.join(testInputs, 'test4_run.json') - with open(testOutput, 'r') as f: + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput = os.path.join(testInputs, "test4_run.json") + with open(testOutput, "r") as f: json = json.load(f) return json @@ -1155,45 +1477,47 @@ def test_json_diff_report_pretty_printing(self): "91 family 1 instance 0 aggregate", "90 family 1 instance 1 repetition 0", "89 family 1 instance 1 repetition 1", - "88 family 1 instance 1 aggregate" + "88 family 1 instance 1 aggregate", ] - for n in range(len(self.json['benchmarks']) ** 2): - random.shuffle(self.json['benchmarks']) + for n in range(len(self.json["benchmarks"]) ** 2): + random.shuffle(self.json["benchmarks"]) sorted_benchmarks = util.sort_benchmark_results(self.json)[ - 'benchmarks'] + "benchmarks" + ] self.assertEqual(len(expected_names), len(sorted_benchmarks)) for out, expected in zip(sorted_benchmarks, expected_names): - self.assertEqual(out['name'], expected) + self.assertEqual(out["name"], expected) def assert_utest(unittest_instance, lhs, rhs): - if lhs['utest']: + if lhs["utest"]: unittest_instance.assertAlmostEqual( - lhs['utest']['cpu_pvalue'], - rhs['utest']['cpu_pvalue']) + lhs["utest"]["cpu_pvalue"], rhs["utest"]["cpu_pvalue"] + ) unittest_instance.assertAlmostEqual( - lhs['utest']['time_pvalue'], - rhs['utest']['time_pvalue']) + lhs["utest"]["time_pvalue"], rhs["utest"]["time_pvalue"] + ) unittest_instance.assertEqual( - lhs['utest']['have_optimal_repetitions'], - rhs['utest']['have_optimal_repetitions']) + lhs["utest"]["have_optimal_repetitions"], + rhs["utest"]["have_optimal_repetitions"], + ) else: # lhs is empty. assert if rhs is not. - unittest_instance.assertEqual(lhs['utest'], rhs['utest']) + unittest_instance.assertEqual(lhs["utest"], rhs["utest"]) def assert_measurements(unittest_instance, lhs, rhs): - for m1, m2 in zip(lhs['measurements'], rhs['measurements']): - unittest_instance.assertEqual(m1['real_time'], m2['real_time']) - unittest_instance.assertEqual(m1['cpu_time'], m2['cpu_time']) + for m1, m2 in zip(lhs["measurements"], rhs["measurements"]): + unittest_instance.assertEqual(m1["real_time"], m2["real_time"]) + unittest_instance.assertEqual(m1["cpu_time"], m2["cpu_time"]) # m1['time'] and m1['cpu'] hold values which are being calculated, # and therefore we must use almost-equal pattern. - unittest_instance.assertAlmostEqual(m1['time'], m2['time'], places=4) - unittest_instance.assertAlmostEqual(m1['cpu'], m2['cpu'], places=4) + unittest_instance.assertAlmostEqual(m1["time"], m2["time"], places=4) + unittest_instance.assertAlmostEqual(m1["cpu"], m2["cpu"], places=4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 5e79da8f01..84747d1053 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -7,13 +7,12 @@ import sys import tempfile - # Input file type enumeration IT_Invalid = 0 IT_JSON = 1 IT_Executable = 2 -_num_magic_bytes = 2 if sys.platform.startswith('win') else 4 +_num_magic_bytes = 2 if sys.platform.startswith("win") else 4 def is_executable_file(filename): @@ -24,21 +23,21 @@ def is_executable_file(filename): """ if not os.path.isfile(filename): return False - with open(filename, mode='rb') as f: + with open(filename, mode="rb") as f: magic_bytes = f.read(_num_magic_bytes) - if sys.platform == 'darwin': + if sys.platform == "darwin": return magic_bytes in [ - b'\xfe\xed\xfa\xce', # MH_MAGIC - b'\xce\xfa\xed\xfe', # MH_CIGAM - b'\xfe\xed\xfa\xcf', # MH_MAGIC_64 - b'\xcf\xfa\xed\xfe', # MH_CIGAM_64 - b'\xca\xfe\xba\xbe', # FAT_MAGIC - b'\xbe\xba\xfe\xca' # FAT_CIGAM + b"\xfe\xed\xfa\xce", # MH_MAGIC + b"\xce\xfa\xed\xfe", # MH_CIGAM + b"\xfe\xed\xfa\xcf", # MH_MAGIC_64 + b"\xcf\xfa\xed\xfe", # MH_CIGAM_64 + b"\xca\xfe\xba\xbe", # FAT_MAGIC + b"\xbe\xba\xfe\xca", # FAT_CIGAM ] - elif sys.platform.startswith('win'): - return magic_bytes == b'MZ' + elif sys.platform.startswith("win"): + return magic_bytes == b"MZ" else: - return magic_bytes == b'\x7FELF' + return magic_bytes == b"\x7FELF" def is_json_file(filename): @@ -47,7 +46,7 @@ def is_json_file(filename): 'False' otherwise. """ try: - with open(filename, 'r') as f: + with open(filename, "r") as f: json.load(f) return True except BaseException: @@ -72,7 +71,10 @@ def classify_input_file(filename): elif is_json_file(filename): ftype = IT_JSON else: - err_msg = "'%s' does not name a valid benchmark executable or JSON file" % filename + err_msg = ( + "'%s' does not name a valid benchmark executable or JSON file" + % filename + ) return ftype, err_msg @@ -95,11 +97,11 @@ def find_benchmark_flag(prefix, benchmark_flags): if it is found return the arg it specifies. If specified more than once the last value is returned. If the flag is not found None is returned. """ - assert prefix.startswith('--') and prefix.endswith('=') + assert prefix.startswith("--") and prefix.endswith("=") result = None for f in benchmark_flags: if f.startswith(prefix): - result = f[len(prefix):] + result = f[len(prefix) :] return result @@ -108,7 +110,7 @@ def remove_benchmark_flags(prefix, benchmark_flags): Return a new list containing the specified benchmark_flags except those with the specified prefix. """ - assert prefix.startswith('--') and prefix.endswith('=') + assert prefix.startswith("--") and prefix.endswith("=") return [f for f in benchmark_flags if not f.startswith(prefix)] @@ -124,36 +126,54 @@ def load_benchmark_results(fname, benchmark_filter): REQUIRES: 'fname' names a file containing JSON benchmark output. """ + def benchmark_wanted(benchmark): if benchmark_filter is None: return True - name = benchmark.get('run_name', None) or benchmark['name'] + name = benchmark.get("run_name", None) or benchmark["name"] if re.search(benchmark_filter, name): return True return False - with open(fname, 'r') as f: + with open(fname, "r") as f: results = json.load(f) - if 'benchmarks' in results: - results['benchmarks'] = list(filter(benchmark_wanted, - results['benchmarks'])) + if "benchmarks" in results: + results["benchmarks"] = list( + filter(benchmark_wanted, results["benchmarks"]) + ) return results def sort_benchmark_results(result): - benchmarks = result['benchmarks'] + benchmarks = result["benchmarks"] # From inner key to the outer key! benchmarks = sorted( - benchmarks, key=lambda benchmark: benchmark['repetition_index'] if 'repetition_index' in benchmark else -1) + benchmarks, + key=lambda benchmark: benchmark["repetition_index"] + if "repetition_index" in benchmark + else -1, + ) benchmarks = sorted( - benchmarks, key=lambda benchmark: 1 if 'run_type' in benchmark and benchmark['run_type'] == "aggregate" else 0) + benchmarks, + key=lambda benchmark: 1 + if "run_type" in benchmark and benchmark["run_type"] == "aggregate" + else 0, + ) benchmarks = sorted( - benchmarks, key=lambda benchmark: benchmark['per_family_instance_index'] if 'per_family_instance_index' in benchmark else -1) + benchmarks, + key=lambda benchmark: benchmark["per_family_instance_index"] + if "per_family_instance_index" in benchmark + else -1, + ) benchmarks = sorted( - benchmarks, key=lambda benchmark: benchmark['family_index'] if 'family_index' in benchmark else -1) + benchmarks, + key=lambda benchmark: benchmark["family_index"] + if "family_index" in benchmark + else -1, + ) - result['benchmarks'] = benchmarks + result["benchmarks"] = benchmarks return result @@ -164,21 +184,21 @@ def run_benchmark(exe_name, benchmark_flags): real time console output. RETURNS: A JSON object representing the benchmark output """ - output_name = find_benchmark_flag('--benchmark_out=', - benchmark_flags) + output_name = find_benchmark_flag("--benchmark_out=", benchmark_flags) is_temp_output = False if output_name is None: is_temp_output = True thandle, output_name = tempfile.mkstemp() os.close(thandle) - benchmark_flags = list(benchmark_flags) + \ - ['--benchmark_out=%s' % output_name] + benchmark_flags = list(benchmark_flags) + [ + "--benchmark_out=%s" % output_name + ] cmd = [exe_name] + benchmark_flags - print("RUNNING: %s" % ' '.join(cmd)) + print("RUNNING: %s" % " ".join(cmd)) exitCode = subprocess.call(cmd) if exitCode != 0: - print('TEST FAILED...') + print("TEST FAILED...") sys.exit(exitCode) json_res = load_benchmark_results(output_name, None) if is_temp_output: @@ -195,9 +215,10 @@ def run_or_load_benchmark(filename, benchmark_flags): """ ftype = check_input_file(filename) if ftype == IT_JSON: - benchmark_filter = find_benchmark_flag('--benchmark_filter=', - benchmark_flags) + benchmark_filter = find_benchmark_flag( + "--benchmark_filter=", benchmark_flags + ) return load_benchmark_results(filename, benchmark_filter) if ftype == IT_Executable: return run_benchmark(filename, benchmark_flags) - raise ValueError('Unknown file type %s' % ftype) + raise ValueError("Unknown file type %s" % ftype) diff --git a/tools/strip_asm.py b/tools/strip_asm.py index d131dc7194..bc3a774a79 100755 --- a/tools/strip_asm.py +++ b/tools/strip_asm.py @@ -4,48 +4,49 @@ strip_asm.py - Cleanup ASM output for the specified file """ -from argparse import ArgumentParser -import sys import os import re +import sys +from argparse import ArgumentParser + def find_used_labels(asm): found = set() - label_re = re.compile("\s*j[a-z]+\s+\.L([a-zA-Z0-9][a-zA-Z0-9_]*)") - for l in asm.splitlines(): - m = label_re.match(l) + label_re = re.compile(r"\s*j[a-z]+\s+\.L([a-zA-Z0-9][a-zA-Z0-9_]*)") + for line in asm.splitlines(): + m = label_re.match(line) if m: - found.add('.L%s' % m.group(1)) + found.add(".L%s" % m.group(1)) return found def normalize_labels(asm): decls = set() label_decl = re.compile("^[.]{0,1}L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)") - for l in asm.splitlines(): - m = label_decl.match(l) + for line in asm.splitlines(): + m = label_decl.match(line) if m: decls.add(m.group(0)) if len(decls) == 0: return asm - needs_dot = next(iter(decls))[0] != '.' + needs_dot = next(iter(decls))[0] != "." if not needs_dot: return asm for ld in decls: - asm = re.sub("(^|\s+)" + ld + "(?=:|\s)", '\\1.' + ld, asm) + asm = re.sub(r"(^|\s+)" + ld + r"(?=:|\s)", "\\1." + ld, asm) return asm def transform_labels(asm): asm = normalize_labels(asm) used_decls = find_used_labels(asm) - new_asm = '' - label_decl = re.compile("^\.L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)") - for l in asm.splitlines(): - m = label_decl.match(l) + new_asm = "" + label_decl = re.compile(r"^\.L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)") + for line in asm.splitlines(): + m = label_decl.match(line) if not m or m.group(0) in used_decls: - new_asm += l - new_asm += '\n' + new_asm += line + new_asm += "\n" return new_asm @@ -53,29 +54,34 @@ def is_identifier(tk): if len(tk) == 0: return False first = tk[0] - if not first.isalpha() and first != '_': + if not first.isalpha() and first != "_": return False for i in range(1, len(tk)): c = tk[i] - if not c.isalnum() and c != '_': + if not c.isalnum() and c != "_": return False return True -def process_identifiers(l): + +def process_identifiers(line): """ process_identifiers - process all identifiers and modify them to have consistent names across all platforms; specifically across ELF and MachO. For example, MachO inserts an additional understore at the beginning of names. This function removes that. """ - parts = re.split(r'([a-zA-Z0-9_]+)', l) - new_line = '' + parts = re.split(r"([a-zA-Z0-9_]+)", line) + new_line = "" for tk in parts: if is_identifier(tk): - if tk.startswith('__Z'): + if tk.startswith("__Z"): tk = tk[1:] - elif tk.startswith('_') and len(tk) > 1 and \ - tk[1].isalpha() and tk[1] != 'Z': + elif ( + tk.startswith("_") + and len(tk) > 1 + and tk[1].isalpha() + and tk[1] != "Z" + ): tk = tk[1:] new_line += tk return new_line @@ -85,65 +91,71 @@ def process_asm(asm): """ Strip the ASM of unwanted directives and lines """ - new_contents = '' + new_contents = "" asm = transform_labels(asm) # TODO: Add more things we want to remove discard_regexes = [ - re.compile("\s+\..*$"), # directive - re.compile("\s*#(NO_APP|APP)$"), #inline ASM - re.compile("\s*#.*$"), # comment line - re.compile("\s*\.globa?l\s*([.a-zA-Z_][a-zA-Z0-9$_.]*)"), #global directive - re.compile("\s*\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)"), - ] - keep_regexes = [ - + re.compile(r"\s+\..*$"), # directive + re.compile(r"\s*#(NO_APP|APP)$"), # inline ASM + re.compile(r"\s*#.*$"), # comment line + re.compile( + r"\s*\.globa?l\s*([.a-zA-Z_][a-zA-Z0-9$_.]*)" + ), # global directive + re.compile( + r"\s*\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)" + ), ] + keep_regexes: list[re.Pattern] = [] fn_label_def = re.compile("^[a-zA-Z_][a-zA-Z0-9_.]*:") - for l in asm.splitlines(): + for line in asm.splitlines(): # Remove Mach-O attribute - l = l.replace('@GOTPCREL', '') + line = line.replace("@GOTPCREL", "") add_line = True for reg in discard_regexes: - if reg.match(l) is not None: + if reg.match(line) is not None: add_line = False break for reg in keep_regexes: - if reg.match(l) is not None: + if reg.match(line) is not None: add_line = True break if add_line: - if fn_label_def.match(l) and len(new_contents) != 0: - new_contents += '\n' - l = process_identifiers(l) - new_contents += l - new_contents += '\n' + if fn_label_def.match(line) and len(new_contents) != 0: + new_contents += "\n" + line = process_identifiers(line) + new_contents += line + new_contents += "\n" return new_contents + def main(): - parser = ArgumentParser( - description='generate a stripped assembly file') + parser = ArgumentParser(description="generate a stripped assembly file") parser.add_argument( - 'input', metavar='input', type=str, nargs=1, - help='An input assembly file') + "input", + metavar="input", + type=str, + nargs=1, + help="An input assembly file", + ) parser.add_argument( - 'out', metavar='output', type=str, nargs=1, - help='The output file') + "out", metavar="output", type=str, nargs=1, help="The output file" + ) args, unknown_args = parser.parse_known_args() input = args.input[0] output = args.out[0] if not os.path.isfile(input): - print(("ERROR: input file '%s' does not exist") % input) + print("ERROR: input file '%s' does not exist" % input) sys.exit(1) - contents = None - with open(input, 'r') as f: + + with open(input, "r") as f: contents = f.read() new_contents = process_asm(contents) - with open(output, 'w') as f: + with open(output, "w") as f: f.write(new_contents) -if __name__ == '__main__': +if __name__ == "__main__": main() # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 From bce46fb413c76ef1744d39477ba4a86e9af1f8ab Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 31 Oct 2023 11:05:37 +0100 Subject: [PATCH 162/561] Drop isort hook for ruff builtin import sorting (#1689) This behaves the same, and saves a pre-commit step. ruff just needs an additional package location hint to correctly map first-part packages (in this case, `google_benchmark`). This revealed a misformat in the `google_benchmark.__init__`, which is now fixed. --- .pre-commit-config.yaml | 5 ----- bindings/python/google_benchmark/__init__.py | 1 + pyproject.toml | 17 +++++++---------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 94ae788f0b..5c4a3df8e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,11 +14,6 @@ repos: rev: 23.10.1 hooks: - id: black - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - args: [--profile, black] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.3 hooks: diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 63b4f6616a..7bdd051cf6 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -29,6 +29,7 @@ def my_benchmark(state): import atexit from absl import app + from google_benchmark import _benchmark from google_benchmark._benchmark import ( Counter, diff --git a/pyproject.toml b/pyproject.toml index 0bac140bb9..861dfcb32b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,12 +61,6 @@ include = "\\.pyi?$" line-length = 80 target-version = ["py311"] -# Black-compatible settings for isort -# See https://black.readthedocs.io/en/stable/ -[tool.isort] -line_length = "80" -profile = "black" - [tool.mypy] check_untyped_defs = true disallow_incomplete_defs = true @@ -80,11 +74,14 @@ module = ["yaml"] ignore_missing_imports = true [tool.ruff] -# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. -select = ["E", "F", "W"] +# explicitly tell ruff the source directory to correctly identify first-party package. +src = ["bindings/python"] +line-length = 80 +# Enable pycodestyle (`E`, `W`), Pyflakes (`F`), and isort (`I`) codes by default. +select = ["E", "F", "I", "W"] ignore = [ - # whitespace before colon (:), rely on black for formatting (in particular, allow spaces before ":" in list/array slices) + # whitespace before colon (:), rely on black for formatting. "E203", - # line too long, rely on black for reformatting of these, since sometimes URLs or comments can be longer + # line too long, rely on black for formatting. "E501", ] From 3623765dd3e8da0828a20201d0cd7d400b22abb0 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Wed, 1 Nov 2023 10:48:01 +0100 Subject: [PATCH 163/561] Add `setuptools_scm` for dynamic zero-config Python versioning (#1690) * Add `setuptools_scm` for dynamic zero-config Python versioning This removes the need for manually bumping versions in the Python bindings. For the wheel uploads, the correct semver version is inferred in the case of tagged commits, which is exactly the case in GitHub CI. The docs were updated to reflect the changes in the release workflow. * Add separate version variable and module, use PEP484-compliant exports This is the best practice mentioned in the `setuptools_scm` docs, see https://setuptools-scm.readthedocs.io/en/latest/usage/#version-at-runtime. --- bindings/python/google_benchmark/__init__.py | 53 ++++++-------------- bindings/python/google_benchmark/version.py | 7 +++ docs/python_bindings.md | 8 +-- docs/releasing.md | 18 ++----- pyproject.toml | 8 ++- 5 files changed, 37 insertions(+), 57 deletions(-) create mode 100644 bindings/python/google_benchmark/version.py diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 7bdd051cf6..e14769f451 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -32,44 +32,23 @@ def my_benchmark(state): from google_benchmark import _benchmark from google_benchmark._benchmark import ( - Counter, - State, - kMicrosecond, - kMillisecond, - kNanosecond, - kSecond, - o1, - oAuto, - oLambda, - oLogN, - oN, - oNCubed, - oNLogN, - oNone, - oNSquared, + Counter as Counter, + State as State, + kMicrosecond as kMicrosecond, + kMillisecond as kMillisecond, + kNanosecond as kNanosecond, + kSecond as kSecond, + o1 as o1, + oAuto as oAuto, + oLambda as oLambda, + oLogN as oLogN, + oN as oN, + oNCubed as oNCubed, + oNLogN as oNLogN, + oNone as oNone, + oNSquared as oNSquared, ) - -__all__ = [ - "register", - "main", - "Counter", - "kNanosecond", - "kMicrosecond", - "kMillisecond", - "kSecond", - "oNone", - "o1", - "oN", - "oNSquared", - "oNCubed", - "oLogN", - "oNLogN", - "oAuto", - "oLambda", - "State", -] - -__version__ = "1.8.3" +from google_benchmark.version import __version__ as __version__ class __OptionMaker: diff --git a/bindings/python/google_benchmark/version.py b/bindings/python/google_benchmark/version.py new file mode 100644 index 0000000000..a324693e2d --- /dev/null +++ b/bindings/python/google_benchmark/version.py @@ -0,0 +1,7 @@ +from importlib.metadata import PackageNotFoundError, version + +try: + __version__ = version("google-benchmark") +except PackageNotFoundError: + # package is not installed + pass diff --git a/docs/python_bindings.md b/docs/python_bindings.md index 6a7aab0a29..d9c5d2d3f6 100644 --- a/docs/python_bindings.md +++ b/docs/python_bindings.md @@ -3,7 +3,7 @@ Python bindings are available as wheels on [PyPI](https://pypi.org/project/google-benchmark/) for importing and using Google Benchmark directly in Python. Currently, pre-built wheels exist for macOS (both ARM64 and Intel x86), Linux x86-64 and 64-bit Windows. -Supported Python versions are Python 3.7 - 3.10. +Supported Python versions are Python 3.8 - 3.12. To install Google Benchmark's Python bindings, run: @@ -25,9 +25,9 @@ python3 -m venv venv --system-site-packages source venv/bin/activate # .\venv\Scripts\Activate.ps1 on Windows # upgrade Python's system-wide packages -python -m pip install --upgrade pip setuptools wheel -# builds the wheel and stores it in the directory "wheelhouse". -python -m pip wheel . -w wheelhouse +python -m pip install --upgrade pip build +# builds the wheel and stores it in the directory "dist". +python -m build ``` NB: Building wheels from source requires Bazel. For platform-specific instructions on how to install Bazel, diff --git a/docs/releasing.md b/docs/releasing.md index cdf415997a..09bf93764d 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -8,9 +8,8 @@ * `git log $(git describe --abbrev=0 --tags)..HEAD` gives you the list of commits between the last annotated tag and HEAD * Pick the most interesting. -* Create one last commit that updates the version saved in `CMakeLists.txt`, `MODULE.bazel` - and the `__version__` variable in `bindings/python/google_benchmark/__init__.py`to the - release version you're creating. (This version will be used if benchmark is installed +* Create one last commit that updates the version saved in `CMakeLists.txt` and `MODULE.bazel` + to the release version you're creating. (This version will be used if benchmark is installed from the archive you'll be creating in the next step.) ``` @@ -21,16 +20,6 @@ project (benchmark VERSION 1.8.0 LANGUAGES CXX) module(name = "com_github_google_benchmark", version="1.8.0") ``` -```python -# bindings/python/google_benchmark/__init__.py - -# ... - -__version__ = "1.8.0" # <-- change this to the release version you are creating - -# ... -``` - * Create a release through github's interface * Note this will create a lightweight tag. * Update this to an annotated tag: @@ -38,4 +27,5 @@ __version__ = "1.8.0" # <-- change this to the release version you are creating * `git tag -a -f ` * `git push --force --tags origin` * Confirm that the "Build and upload Python wheels" action runs to completion - * run it manually if it hasn't run + * Run it manually if it hasn't run. + * IMPORTANT: When re-running manually, make sure to select the newly created `` as the workflow version in the "Run workflow" tab on the GitHub Actions page. diff --git a/pyproject.toml b/pyproject.toml index 861dfcb32b..442cef3620 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools", "wheel"] +requires = ["setuptools>=64", "setuptools-scm[toml]>=8"] build-backend = "setuptools.build_meta" [project] @@ -52,9 +52,10 @@ zip-safe = false where = ["bindings/python"] [tool.setuptools.dynamic] -version = { attr = "google_benchmark.__version__" } readme = { file = "README.md", content-type = "text/markdown" } +[tool.setuptools_scm] + [tool.black] # Source https://github.com/psf/black#configuration-format include = "\\.pyi?$" @@ -85,3 +86,6 @@ ignore = [ # line too long, rely on black for formatting. "E501", ] + +[tool.ruff.isort] +combine-as-imports = true From b40db869451036d222d155bc8cd6420c2fb9527a Mon Sep 17 00:00:00 2001 From: Afanasyev Ivan Date: Wed, 1 Nov 2023 17:09:15 +0700 Subject: [PATCH 164/561] Fix unit tests compilation with non-gnu / non-msvc compilers with c++11 support. (#1691) donotoptimize_test.cc could not be compiled under non-gnu / non-msvc compilers, because only deprecated version of DoNotOptimize is available for these compilers. Tests are compiled with -Werror. Patch fixes test compilation by providing non-deprecated version of DoNotOptimize for compilers with c++11 standard support. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- include/benchmark/benchmark.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 23103571bb..adf219a531 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -584,6 +584,12 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { _ReadWriteBarrier(); } #endif #else +#ifdef BENCHMARK_HAS_CXX11 +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { + internal::UseCharPointer(&reinterpret_cast(value)); +} +#else template BENCHMARK_DEPRECATED_MSG( "The const-ref version of this method can permit " @@ -591,6 +597,12 @@ BENCHMARK_DEPRECATED_MSG( inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { internal::UseCharPointer(&reinterpret_cast(value)); } + +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { + internal::UseCharPointer(&reinterpret_cast(value)); +} +#endif // FIXME Add ClobberMemory() for non-gnu and non-msvc compilers, before C++11. #endif From a543fcd410d737913d78ff8ee39fb8b2df81c0e3 Mon Sep 17 00:00:00 2001 From: Tiago Freire <67021355+tmiguelf@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:09:50 +0100 Subject: [PATCH 165/561] Fixed compiler warnings (#1697) * fixed warnings used proper math functions * ran clang format * used a more up-to-date clang-format * space twedling * reveretd CMakeLists.txt --- src/benchmark_runner.cc | 2 +- src/complexity.cc | 20 ++++++++++++-------- src/counter.cc | 4 ++-- src/cycleclock.h | 7 ++++--- src/statistics.cc | 9 ++++++--- src/sysinfo.cc | 2 +- src/timers.cc | 3 ++- test/complexity_test.cc | 2 +- 8 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index f5cd3e644b..d35bc30d49 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -108,7 +108,7 @@ BenchmarkReporter::Run CreateRunReport( report.memory_result = memory_result; report.allocs_per_iter = memory_iterations ? static_cast(memory_result->num_allocs) / - memory_iterations + static_cast(memory_iterations) : 0; } diff --git a/src/complexity.cc b/src/complexity.cc index 825c57394a..bee362d1d5 100644 --- a/src/complexity.cc +++ b/src/complexity.cc @@ -37,12 +37,14 @@ BigOFunc* FittingCurve(BigO complexity) { return [](IterationCount n) -> double { return std::pow(n, 3); }; case oLogN: /* Note: can't use log2 because Android's GNU STL lacks it */ - return - [](IterationCount n) { return kLog2E * log(static_cast(n)); }; + return [](IterationCount n) { + return kLog2E * std::log(static_cast(n)); + }; case oNLogN: /* Note: can't use log2 because Android's GNU STL lacks it */ return [](IterationCount n) { - return kLog2E * n * log(static_cast(n)); + return kLog2E * static_cast(n) * + std::log(static_cast(n)); }; case o1: default: @@ -105,12 +107,12 @@ LeastSq MinimalLeastSq(const std::vector& n, double rms = 0.0; for (size_t i = 0; i < n.size(); ++i) { double fit = result.coef * fitting_curve(n[i]); - rms += pow((time[i] - fit), 2); + rms += std::pow((time[i] - fit), 2); } // Normalized RMS by the mean of the observed values - double mean = sigma_time / n.size(); - result.rms = sqrt(rms / n.size()) / mean; + double mean = sigma_time / static_cast(n.size()); + result.rms = std::sqrt(rms / static_cast(n.size())) / mean; return result; } @@ -171,8 +173,10 @@ std::vector ComputeBigO( BM_CHECK_GT(run.complexity_n, 0) << "Did you forget to call SetComplexityN?"; n.push_back(run.complexity_n); - real_time.push_back(run.real_accumulated_time / run.iterations); - cpu_time.push_back(run.cpu_accumulated_time / run.iterations); + real_time.push_back(run.real_accumulated_time / + static_cast(run.iterations)); + cpu_time.push_back(run.cpu_accumulated_time / + static_cast(run.iterations)); } LeastSq result_cpu; diff --git a/src/counter.cc b/src/counter.cc index cf5b78ee3a..aa14cd8092 100644 --- a/src/counter.cc +++ b/src/counter.cc @@ -27,10 +27,10 @@ double Finish(Counter const& c, IterationCount iterations, double cpu_time, v /= num_threads; } if (c.flags & Counter::kIsIterationInvariant) { - v *= iterations; + v *= static_cast(iterations); } if (c.flags & Counter::kAvgIterations) { - v /= iterations; + v /= static_cast(iterations); } if (c.flags & Counter::kInvert) { // Invert is *always* last. diff --git a/src/cycleclock.h b/src/cycleclock.h index ae1ef2d2d2..dfc7ae72d5 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -218,9 +218,10 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { asm volatile("%0 = C15:14" : "=r"(pcycle)); return static_cast(pcycle); #else -// The soft failover to a generic implementation is automatic only for ARM. -// For other platforms the developer is expected to make an attempt to create -// a fast implementation and use generic version if nothing better is available. + // The soft failover to a generic implementation is automatic only for ARM. + // For other platforms the developer is expected to make an attempt to create + // a fast implementation and use generic version if nothing better is + // available. #error You need to define CycleTimer for your OS and CPU #endif } diff --git a/src/statistics.cc b/src/statistics.cc index 844e926895..4a639fd2b9 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -32,7 +32,7 @@ auto StatisticsSum = [](const std::vector& v) { double StatisticsMean(const std::vector& v) { if (v.empty()) return 0.0; - return StatisticsSum(v) * (1.0 / v.size()); + return StatisticsSum(v) * (1.0 / static_cast(v.size())); } double StatisticsMedian(const std::vector& v) { @@ -71,8 +71,11 @@ double StatisticsStdDev(const std::vector& v) { // Sample standard deviation is undefined for n = 1 if (v.size() == 1) return 0.0; - const double avg_squares = SumSquares(v) * (1.0 / v.size()); - return Sqrt(v.size() / (v.size() - 1.0) * (avg_squares - Sqr(mean))); + const double avg_squares = + SumSquares(v) * (1.0 / static_cast(v.size())); + return Sqrt(static_cast(v.size()) / + (static_cast(v.size()) - 1.0) * + (avg_squares - Sqr(mean))); } double StatisticsCV(const std::vector& v) { diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 64aa15e072..8875728266 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -655,7 +655,7 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { &freq)) { // The value is in kHz (as the file name suggests). For example, on a // 2GHz warpstation, the file contains the value "2000000". - return freq * 1000.0; + return static_cast(freq) * 1000.0; } const double error_value = -1; diff --git a/src/timers.cc b/src/timers.cc index b23feea8ba..84f48bc2ef 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -102,7 +102,8 @@ double MakeTime(thread_basic_info_data_t const& info) { #endif #if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID) double MakeTime(struct timespec const& ts) { - return ts.tv_sec + (static_cast(ts.tv_nsec) * 1e-9); + return static_cast(ts.tv_sec) + + (static_cast(ts.tv_nsec) * 1e-9); } #endif diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 76891e07b4..1248a535fd 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -175,7 +175,7 @@ BENCHMARK(BM_Complexity_O_N_log_N) ->RangeMultiplier(2) ->Range(1 << 10, 1 << 16) ->Complexity([](benchmark::IterationCount n) { - return kLog2E * static_cast(n) * log(static_cast(n)); + return kLog2E * static_cast(n) * std::log(static_cast(n)); }); BENCHMARK(BM_Complexity_O_N_log_N) ->RangeMultiplier(2) From 159eb2d0ffb85b86e00ec1f983d72e72009ec387 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Fri, 10 Nov 2023 11:40:31 +0100 Subject: [PATCH 166/561] Switch out black for ruff format (#1698) Saves one pre-commit hook, some pyproject.toml configuration, and provides much better performance with almost identical behavior. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .pre-commit-config.yaml | 9 +++------ pyproject.toml | 7 +------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5c4a3df8e2..a1f08341a7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,12 +10,9 @@ repos: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - - repo: https://github.com/psf/black - rev: 23.10.1 - hooks: - - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.3 + rev: v0.1.5 hooks: - id: ruff - args: [ --fix, --exit-non-zero-on-fix ] \ No newline at end of file + args: [ --fix, --exit-non-zero-on-fix ] + - id: ruff-format \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 442cef3620..5e70b3132d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,12 +56,6 @@ readme = { file = "README.md", content-type = "text/markdown" } [tool.setuptools_scm] -[tool.black] -# Source https://github.com/psf/black#configuration-format -include = "\\.pyi?$" -line-length = 80 -target-version = ["py311"] - [tool.mypy] check_untyped_defs = true disallow_incomplete_defs = true @@ -78,6 +72,7 @@ ignore_missing_imports = true # explicitly tell ruff the source directory to correctly identify first-party package. src = ["bindings/python"] line-length = 80 +target-version = "py311" # Enable pycodestyle (`E`, `W`), Pyflakes (`F`), and isort (`I`) codes by default. select = ["E", "F", "I", "W"] ignore = [ From 93a96a26a6ba36894d7fa6f43513708c595ccb5f Mon Sep 17 00:00:00 2001 From: Anjan Roy <45074836+itzmeanjan@users.noreply.github.com> Date: Mon, 13 Nov 2023 21:39:32 +0400 Subject: [PATCH 167/561] Add missing `\n` character at end of error log string (#1700) Closes https://github.com/google/benchmark/issues/1699 Signed-off-by: Anjan Roy --- src/perf_counters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 417acdb18f..d466e27e86 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -254,7 +254,7 @@ bool PerfCounters::IsCounterSupported(const std::string&) { return false; } PerfCounters PerfCounters::Create( const std::vector& counter_names) { if (!counter_names.empty()) { - GetErrorLogInstance() << "Performance counters not supported."; + GetErrorLogInstance() << "Performance counters not supported.\n"; } return NoCounters(); } From 4a2e34ba7342c780a11e3b5e809cc70b2cac0861 Mon Sep 17 00:00:00 2001 From: illbegood Date: Thu, 16 Nov 2023 16:55:59 +0700 Subject: [PATCH 168/561] Fix CMakeLists.txt for perf_counters_test (#1701) --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c262236419..e7f738f6cb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -164,7 +164,7 @@ compile_output_test(user_counters_test) add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s) compile_output_test(perf_counters_test) -add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,BRANCHES) +add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,INSTRUCTIONS) compile_output_test(internal_threading_test) add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01s) From c8ef1ee99eca565f6a58a9f815fba5ef1f210783 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 23 Nov 2023 11:45:02 +0300 Subject: [PATCH 169/561] [CI] Try to fix sanitizer builds by pinning the LLVM revision (#1703) --- .github/libcxx-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/libcxx-setup.sh b/.github/libcxx-setup.sh index 8773b9c407..9aaf96af4b 100755 --- a/.github/libcxx-setup.sh +++ b/.github/libcxx-setup.sh @@ -3,7 +3,7 @@ set -e # Checkout LLVM sources -git clone --depth=1 https://github.com/llvm/llvm-project.git llvm-project +git clone --depth=1 --branch llvmorg-16.0.6 https://github.com/llvm/llvm-project.git llvm-project ## Setup libc++ options if [ -z "$BUILD_32_BITS" ]; then From 1e96bb0ab5e758861f5bbbd4edbd0a8d9a2a7cae Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 23 Nov 2023 17:47:04 +0300 Subject: [PATCH 170/561] Support windows MSYS2 environments (#1704) * [CI] Attempt to add windows MSYS2-based coverage * Mark decl of `State::KeepRunningInternal()` as `inline` Maybe helps with ``` D:\a\_temp\msys64\ucrt64\bin\g++.exe -DHAVE_STD_REGEX -DHAVE_STEADY_CLOCK -DTEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS -ID:/a/benchmark/benchmark/include -Wall -Wextra -Wshadow -Wfloat-equal -Wold-style-cast -Werror -pedantic -pedantic-errors -fstrict-aliasing -Wno-deprecated-declarations -Wno-deprecated -Wstrict-aliasing -Wno-unused-variable -std=c++11 -fvisibility=hidden -fno-keep-inline-dllexport -UNDEBUG -MD -MT test/CMakeFiles/benchmark_test.dir/benchmark_test.cc.obj -MF test\CMakeFiles\benchmark_test.dir\benchmark_test.cc.obj.d -o test/CMakeFiles/benchmark_test.dir/benchmark_test.cc.obj -c D:/a/benchmark/benchmark/test/benchmark_test.cc In file included from D:/a/benchmark/benchmark/test/benchmark_test.cc:1: D:/a/benchmark/benchmark/include/benchmark/benchmark.h:1007:37: error: 'bool benchmark::State::KeepRunningInternal(benchmark::IterationCount, bool)' redeclared without dllimport attribute after being referenced with dll linkage [-Werror] 1007 | inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n, | ^~~~~ ``` * Mark more `State`'s member function decls as `inline` ``` [27/110] Building CXX object test/CMakeFiles/spec_arg_verbosity_test.dir/spec_arg_verbosity_test.cc.obj FAILED: test/CMakeFiles/spec_arg_verbosity_test.dir/spec_arg_verbosity_test.cc.obj D:\a\_temp\msys64\clang32\bin\clang++.exe -DHAVE_STD_REGEX -DHAVE_STEADY_CLOCK -DHAVE_THREAD_SAFETY_ATTRIBUTES -DTEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS -ID:/a/benchmark/benchmark/include -Wall -Wextra -Wshadow -Wfloat-equal -Wold-style-cast -Werror -pedantic -pedantic-errors -Wshorten-64-to-32 -fstrict-aliasing -Wno-deprecated-declarations -Wno-deprecated -Wstrict-aliasing -Wthread-safety -Wno-unused-variable -std=c++11 -fvisibility=hidden -fvisibility-inlines-hidden -UNDEBUG -MD -MT test/CMakeFiles/spec_arg_verbosity_test.dir/spec_arg_verbosity_test.cc.obj -MF test\CMakeFiles\spec_arg_verbosity_test.dir\spec_arg_verbosity_test.cc.obj.d -o test/CMakeFiles/spec_arg_verbosity_test.dir/spec_arg_verbosity_test.cc.obj -c D:/a/benchmark/benchmark/test/spec_arg_verbosity_test.cc In file included from D:/a/benchmark/benchmark/test/spec_arg_verbosity_test.cc:5: D:/a/benchmark/benchmark/include/benchmark/benchmark.h:999:44: error: 'benchmark::State::KeepRunning' redeclared inline; 'dllimport' attribute ignored [-Werror,-Wignored-attributes] 999 | inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunning() { | ^ D:/a/benchmark/benchmark/include/benchmark/benchmark.h:1003:44: error: 'benchmark::State::KeepRunningBatch' redeclared inline; 'dllimport' attribute ignored [-Werror,-Wignored-attributes] 1003 | inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningBatch(IterationCount n) { | ^ D:/a/benchmark/benchmark/include/benchmark/benchmark.h:1075:60: error: 'benchmark::State::begin' redeclared inline; 'dllimport' attribute ignored [-Werror,-Wignored-attributes] 1075 | inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::begin() { | ^ D:/a/benchmark/benchmark/include/benchmark/benchmark.h:1078:60: error: 'benchmark::State::end' redeclared inline; 'dllimport' attribute ignored [-Werror,-Wignored-attributes] 1078 | inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { | ^ ``` * StatisticsTest.CV: don't require precise FP match, tolerate some abs error We get ever so slightly different results on windows with GCC. ``` 71: Test command: D:\a\benchmark\benchmark\_build\test\statistics_gtest.exe 71: Working Directory: D:/a/benchmark/benchmark/_build/test 71: Test timeout computed to be: 10000000 71: Running main() from gmock_main.cc 71: [==========] Running 4 tests from 1 test suite. 71: [----------] Global test environment set-up. 71: [----------] 4 tests from StatisticsTest 71: [ RUN ] StatisticsTest.Mean 71: [ OK ] StatisticsTest.Mean (0 ms) 71: [ RUN ] StatisticsTest.Median 71: [ OK ] StatisticsTest.Median (0 ms) 71: [ RUN ] StatisticsTest.StdDev 71: [ OK ] StatisticsTest.StdDev (0 ms) 71: [ RUN ] StatisticsTest.CV 71: D:/a/benchmark/benchmark/test/statistics_gtest.cc:31: Failure 71: Expected equality of these values: 71: benchmark::StatisticsCV({2.5, 2.4, 3.3, 4.2, 5.1}) 71: Which is: 0.32888184094918088 71: 0.32888184094918121 71: [ FAILED ] StatisticsTest.CV (0 ms) 71: [----------] 4 tests from StatisticsTest (0 ms total) ``` * Fix DLL path discovery for tests --- .github/workflows/build-and-test.yml | 59 ++++++++++++++++++--- include/benchmark/benchmark.h | 10 ++-- test/CMakeLists.txt | 79 ++++++++++++++++------------ test/statistics_gtest.cc | 4 +- 4 files changed, 106 insertions(+), 46 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b35200a000..95e0482aea 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -102,13 +102,60 @@ jobs: - name: build run: cmake --build _build/ --config ${{ matrix.build_type }} - - name: setup test environment - # Make sure gmock and benchmark DLLs can be found - run: > - echo "$((Get-Item .).FullName)/_build/bin/${{ matrix.build_type }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append; - echo "$((Get-Item .).FullName)/_build/src/${{ matrix.build_type }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append; - - name: test run: ctest --test-dir _build/ -C ${{ matrix.build_type }} -VV + msys2: + name: ${{ matrix.os }}.${{ matrix.build_type }}.${{ matrix.lib }}.${{ matrix.msys2.msystem }} + runs-on: ${{ matrix.os }} + defaults: + run: + shell: msys2 {0} + strategy: + fail-fast: false + matrix: + os: [ windows-latest ] + msys2: + - { msystem: MINGW64, arch: x86_64, family: GNU, compiler: g++ } + - { msystem: MINGW32, arch: i686, family: GNU, compiler: g++ } + - { msystem: CLANG64, arch: x86_64, family: LLVM, compiler: clang++ } + - { msystem: CLANG32, arch: i686, family: LLVM, compiler: clang++ } + - { msystem: UCRT64, arch: x86_64, family: GNU, compiler: g++ } + build_type: + - Debug + - Release + lib: + - shared + - static + + steps: + - uses: actions/checkout@v2 + - name: Install Base Dependencies + uses: msys2/setup-msys2@v2 + with: + cache: false + msystem: ${{ matrix.msys2.msystem }} + update: true + install: >- + git + base-devel + pacboy: >- + cc:p + cmake:p + ninja:p + + - name: configure cmake + env: + CXX: ${{ matrix.msys2.compiler }} + run: > + cmake -S . -B _build/ + -GNinja + -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON + -DBUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} + + - name: build + run: cmake --build _build/ --config ${{ matrix.build_type }} + + - name: test + run: ctest --test-dir _build/ -C ${{ matrix.build_type }} -VV diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index adf219a531..69ee5e47bb 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -746,13 +746,13 @@ class BENCHMARK_EXPORT State { // have been called previously. // // NOTE: KeepRunning may not be used after calling either of these functions. - BENCHMARK_ALWAYS_INLINE StateIterator begin(); - BENCHMARK_ALWAYS_INLINE StateIterator end(); + inline BENCHMARK_ALWAYS_INLINE StateIterator begin(); + inline BENCHMARK_ALWAYS_INLINE StateIterator end(); // Returns true if the benchmark should continue through another iteration. // NOTE: A benchmark may not return from the test until KeepRunning() has // returned false. - bool KeepRunning(); + inline bool KeepRunning(); // Returns true iff the benchmark should run n more iterations. // REQUIRES: 'n' > 0. @@ -764,7 +764,7 @@ class BENCHMARK_EXPORT State { // while (state.KeepRunningBatch(1000)) { // // process 1000 elements // } - bool KeepRunningBatch(IterationCount n); + inline bool KeepRunningBatch(IterationCount n); // REQUIRES: timer is running and 'SkipWithMessage(...)' or // 'SkipWithError(...)' has not been called by the current thread. @@ -982,7 +982,7 @@ class BENCHMARK_EXPORT State { void StartKeepRunning(); // Implementation of KeepRunning() and KeepRunningBatch(). // is_batch must be true unless n is 1. - bool KeepRunningInternal(IterationCount n, bool is_batch); + inline bool KeepRunningInternal(IterationCount n, bool is_batch); void FinishKeepRunning(); const std::string name_; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e7f738f6cb..d211908432 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -64,30 +64,38 @@ macro(compile_output_test name) ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) endmacro(compile_output_test) +macro(benchmark_add_test) + add_test(${ARGV}) + if(WIN32 AND BUILD_SHARED_LIBS) + cmake_parse_arguments(TEST "" "NAME" "" ${ARGN}) + set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") + endif() +endmacro(compile_output_test) + # Demonstration executable compile_benchmark_test(benchmark_test) -add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01s) compile_benchmark_test(spec_arg_test) -add_test(NAME spec_arg COMMAND spec_arg_test --benchmark_filter=BM_NotChosen) +benchmark_add_test(NAME spec_arg COMMAND spec_arg_test --benchmark_filter=BM_NotChosen) compile_benchmark_test(spec_arg_verbosity_test) -add_test(NAME spec_arg_verbosity COMMAND spec_arg_verbosity_test --v=42) +benchmark_add_test(NAME spec_arg_verbosity COMMAND spec_arg_verbosity_test --v=42) compile_benchmark_test(benchmark_setup_teardown_test) -add_test(NAME benchmark_setup_teardown COMMAND benchmark_setup_teardown_test) +benchmark_add_test(NAME benchmark_setup_teardown COMMAND benchmark_setup_teardown_test) compile_benchmark_test(filter_test) macro(add_filter_test name filter expect) - add_test(NAME ${name} COMMAND filter_test --benchmark_min_time=0.01s --benchmark_filter=${filter} ${expect}) - add_test(NAME ${name}_list_only COMMAND filter_test --benchmark_list_tests --benchmark_filter=${filter} ${expect}) + benchmark_add_test(NAME ${name} COMMAND filter_test --benchmark_min_time=0.01s --benchmark_filter=${filter} ${expect}) + benchmark_add_test(NAME ${name}_list_only COMMAND filter_test --benchmark_list_tests --benchmark_filter=${filter} ${expect}) endmacro(add_filter_test) compile_benchmark_test(benchmark_min_time_flag_time_test) -add_test(NAME min_time_flag_time COMMAND benchmark_min_time_flag_time_test) +benchmark_add_test(NAME min_time_flag_time COMMAND benchmark_min_time_flag_time_test) compile_benchmark_test(benchmark_min_time_flag_iters_test) -add_test(NAME min_time_flag_iters COMMAND benchmark_min_time_flag_iters_test) +benchmark_add_test(NAME min_time_flag_iters COMMAND benchmark_min_time_flag_iters_test) add_filter_test(filter_simple "Foo" 3) add_filter_test(filter_simple_negative "-Foo" 2) @@ -109,19 +117,19 @@ add_filter_test(filter_regex_end ".*Ba$" 1) add_filter_test(filter_regex_end_negative "-.*Ba$" 4) compile_benchmark_test(options_test) -add_test(NAME options_benchmarks COMMAND options_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME options_benchmarks COMMAND options_test --benchmark_min_time=0.01s) compile_benchmark_test(basic_test) -add_test(NAME basic_benchmark COMMAND basic_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME basic_benchmark COMMAND basic_test --benchmark_min_time=0.01s) compile_output_test(repetitions_test) -add_test(NAME repetitions_benchmark COMMAND repetitions_test --benchmark_min_time=0.01s --benchmark_repetitions=3) +benchmark_add_test(NAME repetitions_benchmark COMMAND repetitions_test --benchmark_min_time=0.01s --benchmark_repetitions=3) compile_benchmark_test(diagnostics_test) -add_test(NAME diagnostics_test COMMAND diagnostics_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME diagnostics_test COMMAND diagnostics_test --benchmark_min_time=0.01s) compile_benchmark_test(skip_with_error_test) -add_test(NAME skip_with_error_test COMMAND skip_with_error_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME skip_with_error_test COMMAND skip_with_error_test --benchmark_min_time=0.01s) compile_benchmark_test(donotoptimize_test) # Enable errors for deprecated deprecations (DoNotOptimize(Tp const& value)). @@ -134,55 +142,55 @@ check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) if (BENCHMARK_HAS_O3_FLAG) set_target_properties(donotoptimize_test PROPERTIES COMPILE_FLAGS "-O3") endif() -add_test(NAME donotoptimize_test COMMAND donotoptimize_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME donotoptimize_test COMMAND donotoptimize_test --benchmark_min_time=0.01s) compile_benchmark_test(fixture_test) -add_test(NAME fixture_test COMMAND fixture_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME fixture_test COMMAND fixture_test --benchmark_min_time=0.01s) compile_benchmark_test(register_benchmark_test) -add_test(NAME register_benchmark_test COMMAND register_benchmark_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME register_benchmark_test COMMAND register_benchmark_test --benchmark_min_time=0.01s) compile_benchmark_test(map_test) -add_test(NAME map_test COMMAND map_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME map_test COMMAND map_test --benchmark_min_time=0.01s) compile_benchmark_test(multiple_ranges_test) -add_test(NAME multiple_ranges_test COMMAND multiple_ranges_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME multiple_ranges_test COMMAND multiple_ranges_test --benchmark_min_time=0.01s) compile_benchmark_test(args_product_test) -add_test(NAME args_product_test COMMAND args_product_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME args_product_test COMMAND args_product_test --benchmark_min_time=0.01s) compile_benchmark_test_with_main(link_main_test) -add_test(NAME link_main_test COMMAND link_main_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME link_main_test COMMAND link_main_test --benchmark_min_time=0.01s) compile_output_test(reporter_output_test) -add_test(NAME reporter_output_test COMMAND reporter_output_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME reporter_output_test COMMAND reporter_output_test --benchmark_min_time=0.01s) compile_output_test(templated_fixture_test) -add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01s) compile_output_test(user_counters_test) -add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s) compile_output_test(perf_counters_test) -add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,INSTRUCTIONS) +benchmark_add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,INSTRUCTIONS) compile_output_test(internal_threading_test) -add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01s) compile_output_test(report_aggregates_only_test) -add_test(NAME report_aggregates_only_test COMMAND report_aggregates_only_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME report_aggregates_only_test COMMAND report_aggregates_only_test --benchmark_min_time=0.01s) compile_output_test(display_aggregates_only_test) -add_test(NAME display_aggregates_only_test COMMAND display_aggregates_only_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME display_aggregates_only_test COMMAND display_aggregates_only_test --benchmark_min_time=0.01s) compile_output_test(user_counters_tabular_test) -add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.01s) +benchmark_add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.01s) compile_output_test(user_counters_thousands_test) -add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test --benchmark_min_time=0.01s) compile_output_test(memory_manager_test) -add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s) # MSVC does not allow to set the language standard to C++98/03. if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) @@ -207,7 +215,7 @@ if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) set(DISABLE_LTO_WARNINGS "${DISABLE_LTO_WARNINGS} -Wno-lto-type-mismatch") endif() set_target_properties(cxx03_test PROPERTIES LINK_FLAGS "${DISABLE_LTO_WARNINGS}") - add_test(NAME cxx03 COMMAND cxx03_test --benchmark_min_time=0.01s) + benchmark_add_test(NAME cxx03 COMMAND cxx03_test --benchmark_min_time=0.01s) endif() # Attempt to work around flaky test failures when running on Appveyor servers. @@ -217,7 +225,7 @@ else() set(COMPLEXITY_MIN_TIME "0.01s") endif() compile_output_test(complexity_test) -add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=${COMPLEXITY_MIN_TIME}) +benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=${COMPLEXITY_MIN_TIME}) ############################################################################### # GoogleTest Unit Tests @@ -232,7 +240,12 @@ if (BENCHMARK_ENABLE_GTEST_TESTS) macro(add_gtest name) compile_gtest(${name}) - add_test(NAME ${name} COMMAND ${name}) + benchmark_add_test(NAME ${name} COMMAND ${name}) + if(WIN32 AND BUILD_SHARED_LIBS) + set_tests_properties(${name} PROPERTIES + ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$;PATH=path_list_prepend:$" + ) + endif() endmacro() add_gtest(benchmark_gtest) diff --git a/test/statistics_gtest.cc b/test/statistics_gtest.cc index 1de2d87d4b..48c77260fd 100644 --- a/test/statistics_gtest.cc +++ b/test/statistics_gtest.cc @@ -28,8 +28,8 @@ TEST(StatisticsTest, StdDev) { TEST(StatisticsTest, CV) { EXPECT_DOUBLE_EQ(benchmark::StatisticsCV({101, 101, 101, 101}), 0.0); EXPECT_DOUBLE_EQ(benchmark::StatisticsCV({1, 2, 3}), 1. / 2.); - EXPECT_DOUBLE_EQ(benchmark::StatisticsCV({2.5, 2.4, 3.3, 4.2, 5.1}), - 0.32888184094918121); + ASSERT_NEAR(benchmark::StatisticsCV({2.5, 2.4, 3.3, 4.2, 5.1}), + 0.32888184094918121, 1e-15); } } // end namespace From 68689bf9660110ab1368d55b2b6a66dbb3e811cf Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Thu, 7 Dec 2023 10:41:34 +0100 Subject: [PATCH 171/561] Fix `pre-commit` GitHub Actions job (#1708) For some reason, editable pip installs are now broken, which means that they will break the pre-commit workflow due to the `pip install -e .` instruction. Since the normal install is unaffected, we can just drop the `-e` switch. It does not matter which mode is used, since the environment is only used for linting. --- .github/workflows/pre-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index f78a90d874..8b3442c583 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -25,7 +25,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + pip install ".[dev]" - name: Cache pre-commit tools uses: actions/cache@v3 with: From 50560985db2d468b871b90f7920d49e785e19b81 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 7 Dec 2023 13:40:56 +0300 Subject: [PATCH 172/561] [NFC] `complexity_n` is not of `IterationCount` type (#1709) There is no bug here, but it gave me a scare the other day. It is not incorrect to use `IterationCount` here, since it's just an `int64_t` either way, but it's wildly confusing. Let's not do that. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- include/benchmark/benchmark.h | 14 +++++++++----- src/complexity.cc | 8 ++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 69ee5e47bb..9849c4287a 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -672,13 +672,15 @@ typedef std::map UserCounters; // calculated automatically to the best fit. enum BigO { oNone, o1, oN, oNSquared, oNCubed, oLogN, oNLogN, oAuto, oLambda }; +typedef int64_t ComplexityN; + typedef int64_t IterationCount; enum StatisticUnit { kTime, kPercentage }; // BigOFunc is passed to a benchmark in order to specify the asymptotic // computational complexity for the benchmark. -typedef double(BigOFunc)(IterationCount); +typedef double(BigOFunc)(ComplexityN); // StatisticsFunc is passed to a benchmark in order to compute some descriptive // statistics over all the measurements of some type @@ -875,10 +877,12 @@ class BENCHMARK_EXPORT State { // and complexity_n will // represent the length of N. BENCHMARK_ALWAYS_INLINE - void SetComplexityN(int64_t complexity_n) { complexity_n_ = complexity_n; } + void SetComplexityN(ComplexityN complexity_n) { + complexity_n_ = complexity_n; + } BENCHMARK_ALWAYS_INLINE - int64_t complexity_length_n() const { return complexity_n_; } + ComplexityN complexity_length_n() const { return complexity_n_; } // If this routine is called with items > 0, then an items/s // label is printed on the benchmark report line for the currently @@ -967,7 +971,7 @@ class BENCHMARK_EXPORT State { // items we don't need on the first cache line std::vector range_; - int64_t complexity_n_; + ComplexityN complexity_n_; public: // Container for user-defined counters. @@ -1805,7 +1809,7 @@ class BENCHMARK_EXPORT BenchmarkReporter { // Keep track of arguments to compute asymptotic complexity BigO complexity; BigOFunc* complexity_lambda; - int64_t complexity_n; + ComplexityN complexity_n; // what statistics to compute from the measurements const std::vector* statistics; diff --git a/src/complexity.cc b/src/complexity.cc index bee362d1d5..e53dd342d1 100644 --- a/src/complexity.cc +++ b/src/complexity.cc @@ -77,12 +77,12 @@ std::string GetBigOString(BigO complexity) { // given by the lambda expression. // - n : Vector containing the size of the benchmark tests. // - time : Vector containing the times for the benchmark tests. -// - fitting_curve : lambda expression (e.g. [](int64_t n) {return n; };). +// - fitting_curve : lambda expression (e.g. [](ComplexityN n) {return n; };). // For a deeper explanation on the algorithm logic, please refer to // https://en.wikipedia.org/wiki/Least_squares#Least_squares,_regression_analysis_and_statistics -LeastSq MinimalLeastSq(const std::vector& n, +LeastSq MinimalLeastSq(const std::vector& n, const std::vector& time, BigOFunc* fitting_curve) { double sigma_gn_squared = 0.0; @@ -124,7 +124,7 @@ LeastSq MinimalLeastSq(const std::vector& n, // - complexity : If different than oAuto, the fitting curve will stick to // this one. If it is oAuto, it will be calculated the best // fitting curve. -LeastSq MinimalLeastSq(const std::vector& n, +LeastSq MinimalLeastSq(const std::vector& n, const std::vector& time, const BigO complexity) { BM_CHECK_EQ(n.size(), time.size()); BM_CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two @@ -164,7 +164,7 @@ std::vector ComputeBigO( if (reports.size() < 2) return results; // Accumulators. - std::vector n; + std::vector n; std::vector real_time; std::vector cpu_time; From e2c13db77a64a1b631640b88c7f422c22c137a2d Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Thu, 7 Dec 2023 13:35:20 +0100 Subject: [PATCH 173/561] Fix editable install by unsetting `build_ext.copy_extensions_to_source` (#1710) This method was the culprit for the recent editable install breakage, since it just tries to copy the generated extension file without checking its existence. Since the `BazelExtension` uses a non-standard location to store the build artifacts, calling the copy method fails the build since the extension is not found in the expected location. But, since we already copy the file into the source tree as part of the `BazelExtension.bazel_build` method, it's fine - the extension appears in the right place, and the egg info is generated correctly as well. This method also does not affect the general install, so it solves the editable problem without regressing the fixed install. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- setup.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/setup.py b/setup.py index f4700a025a..4d8414180d 100644 --- a/setup.py +++ b/setup.py @@ -57,6 +57,14 @@ def run(self): # explicitly call `bazel shutdown` for graceful exit self.spawn(["bazel", "shutdown"]) + def copy_extensions_to_source(self): + """ + Copy generated extensions into the source tree. + This is done in the ``bazel_build`` method, so it's not necessary to + do again in the `build_ext` base class. + """ + pass + def bazel_build(self, ext: BazelExtension) -> None: """Runs the bazel build to create the package.""" with temp_fill_include_path("WORKSPACE"): From 754ef08ab91767be54f56e8de3f00527aef3f779 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Thu, 7 Dec 2023 16:00:43 +0100 Subject: [PATCH 174/561] Upgrade core bazel dependencies (#1711) Bumps `rules_foreign_cc` to v0.10.1 (October 2023), `bazel_skylib` to v1.5.0 (November 2023), `rules_python` to v0.27.1 (December 2023). Also syncs GoogleTest to v1.12.1 (the last C++11 supporting version) to be the same as in MODULE.bazel. Since the latest `rules_python` changed its setup calling convention, that is updated also in the WORKSPACE file. --- MODULE.bazel | 6 +++--- WORKSPACE | 14 +++++++++++--- bazel/benchmark_deps.bzl | 30 +++++++++++------------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 8dd3d83193..cdac6c899c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -3,12 +3,12 @@ module( version = "1.8.3", ) -bazel_dep(name = "bazel_skylib", version = "1.4.2") +bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "platforms", version = "0.0.6") -bazel_dep(name = "rules_foreign_cc", version = "0.9.0") +bazel_dep(name = "rules_foreign_cc", version = "0.10.1") bazel_dep(name = "rules_cc", version = "0.0.6") -bazel_dep(name = "rules_python", version = "0.24.0", dev_dependency = True) +bazel_dep(name = "rules_python", version = "0.27.1", dev_dependency = True) bazel_dep(name = "googletest", version = "1.12.1", dev_dependency = True, repo_name = "com_google_googletest") bazel_dep(name = "libpfm", version = "4.11.0") diff --git a/WORKSPACE b/WORKSPACE index a9cf5b379f..2562070225 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,13 +8,21 @@ load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_depende rules_foreign_cc_dependencies() -load("@rules_python//python:pip.bzl", pip3_install = "pip_install") +load("@rules_python//python:repositories.bzl", "py_repositories") -pip3_install( +py_repositories() + +load("@rules_python//python:pip.bzl", "pip_parse") + +pip_parse( name = "tools_pip_deps", - requirements = "//tools:requirements.txt", + requirements_lock = "//tools:requirements.txt", ) +load("@tools_pip_deps//:requirements.bzl", "install_deps") + +install_deps() + new_local_repository( name = "python_headers", build_file = "@//bindings/python:python_headers.BUILD", diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 91a3674224..4fb45a538d 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -11,49 +11,41 @@ def benchmark_deps(): if "bazel_skylib" not in native.existing_rules(): http_archive( name = "bazel_skylib", - sha256 = "66ffd9315665bfaafc96b52278f57c7e2dd09f5ede279ea6d39b2be471e7e3aa", + sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", ], ) if "rules_foreign_cc" not in native.existing_rules(): http_archive( name = "rules_foreign_cc", - sha256 = "2a4d07cd64b0719b39a7c12218a3e507672b82a97b98c6a89d38565894cf7c51", - strip_prefix = "rules_foreign_cc-0.9.0", - url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.9.0.tar.gz", + sha256 = "476303bd0f1b04cc311fc258f1708a5f6ef82d3091e53fd1977fa20383425a6a", + strip_prefix = "rules_foreign_cc-0.10.1", + url = "https://github.com/bazelbuild/rules_foreign_cc/releases/download/0.10.1/rules_foreign_cc-0.10.1.tar.gz", ) if "rules_python" not in native.existing_rules(): http_archive( name = "rules_python", - sha256 = "0a8003b044294d7840ac7d9d73eef05d6ceb682d7516781a4ec62eeb34702578", - url = "https://github.com/bazelbuild/rules_python/releases/download/0.24.0/rules_python-0.24.0.tar.gz", - strip_prefix = "rules_python-0.24.0", - ) - - if "com_google_absl" not in native.existing_rules(): - http_archive( - name = "com_google_absl", - sha256 = "f41868f7a938605c92936230081175d1eae87f6ea2c248f41077c8f88316f111", - strip_prefix = "abseil-cpp-20200225.2", - urls = ["https://github.com/abseil/abseil-cpp/archive/20200225.2.tar.gz"], + sha256 = "e85ae30de33625a63eca7fc40a94fea845e641888e52f32b6beea91e8b1b2793", + strip_prefix = "rules_python-0.27.1", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.27.1/rules_python-0.27.1.tar.gz", ) if "com_google_googletest" not in native.existing_rules(): new_git_repository( name = "com_google_googletest", remote = "https://github.com/google/googletest.git", - tag = "release-1.11.0", + tag = "release-1.12.1", ) if "nanobind" not in native.existing_rules(): new_git_repository( name = "nanobind", remote = "https://github.com/wjakob/nanobind.git", - tag = "v1.7.0", + tag = "v1.8.0", build_file = "@//bindings/python:nanobind.BUILD", recursive_init_submodules = True, ) From c2de5261302fa307ebe06b24c0fc30653bed5e17 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Wed, 13 Dec 2023 15:26:15 +0100 Subject: [PATCH 175/561] Run `pre-commit autoupdate`, fix stale pyproject.toml comments (#1712) * Run `pre-commit autoupdate`, fix stale pyproject.toml comments * Set `--enable_bzlmod=false` for the moment Until the newer nanobind tags are pushed to the BCR, it's best to disable bzlmod for the bindings, because the Python CI breaks due to Bazel 7 enabling bzlmod by default. * Remove E203 ignore, add linebreaks to semantically group ruff options --- .pre-commit-config.yaml | 6 +++--- pyproject.toml | 7 +++---- setup.py | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a1f08341a7..a58a5cff0d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 6.3.3.1 + rev: 6.4.0 hooks: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.1 + rev: v1.7.1 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.5 + rev: v0.1.7 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/pyproject.toml b/pyproject.toml index 5e70b3132d..92c35066e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,15 +71,14 @@ ignore_missing_imports = true [tool.ruff] # explicitly tell ruff the source directory to correctly identify first-party package. src = ["bindings/python"] + line-length = 80 target-version = "py311" + # Enable pycodestyle (`E`, `W`), Pyflakes (`F`), and isort (`I`) codes by default. select = ["E", "F", "I", "W"] ignore = [ - # whitespace before colon (:), rely on black for formatting. - "E203", - # line too long, rely on black for formatting. - "E501", + "E501", # line too long ] [tool.ruff.isort] diff --git a/setup.py b/setup.py index 4d8414180d..cb20042da5 100644 --- a/setup.py +++ b/setup.py @@ -74,6 +74,7 @@ def bazel_build(self, ext: BazelExtension) -> None: "bazel", "build", ext.bazel_target, + "--enable_bzlmod=false", f"--symlink_prefix={temp_path / 'bazel-'}", f"--compilation_mode={'dbg' if self.debug else 'opt'}", # C++17 is required by nanobind From 9a0422eb2319cbfa9e6dd9915ab212478cfcf83a Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 19 Dec 2023 15:13:08 +0100 Subject: [PATCH 176/561] Check out repo at depth 0 for Python tests, bump Python and PyPI actions (#1713) The reason for this is that `setuptools-scm` installs a version relative to the last release tag - if no tag is found, the default version is taken to be v0.1.0. This was the case in GitHub Actions, where only the PR branch is checked out. Also unpins build system requirements in the `pyproject.toml`. The sdist build system was changed to `build` from `python setup.py sdist` for forward compatibility - `build` is superior in every way, and the advertised solution by both cibuildwheel and PyPA itself. Bump `actions/setup-python` to v5, `pypa/gh-action-pypi-publish` to v1.8.11, and `docker/setup-qemu-action` to v3. --- .github/workflows/pre-commit.yml | 13 ++++++------- .github/workflows/test_bindings.yml | 10 +++++----- .github/workflows/wheels.yml | 23 ++++++++++++----------- pyproject.toml | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 8b3442c583..5d65b9948f 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -16,16 +16,16 @@ jobs: steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 - cache: 'pip' + cache: pip cache-dependency-path: pyproject.toml - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install ".[dev]" + run: python -m pip install ".[dev]" - name: Cache pre-commit tools uses: actions/cache@v3 with: @@ -35,5 +35,4 @@ jobs: ${{ env.PRE_COMMIT_HOME }} key: ${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}-linter-cache - name: Run pre-commit checks - run: | - pre-commit run --all-files --verbose --show-diff-on-failure + run: pre-commit run --all-files --verbose --show-diff-on-failure diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index a287f72901..436a8f90e5 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -17,14 +17,14 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v4 + with: + fetch-depth: 0 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 with: python-version: 3.11 - name: Install GBM Python bindings on ${{ matrix.os }} - run: | - python -m pip install --upgrade pip setuptools wheel - python -m pip install . + run: python -m pip install . - name: Run bindings example on ${{ matrix.os }} run: python bindings/python/google_benchmark/example.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b7c4da7134..a36d312aa6 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -13,17 +13,16 @@ jobs: steps: - name: Check out repo uses: actions/checkout@v4 - + with: + fetch-depth: 0 - name: Install Python 3.11 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 - - - name: Build and check sdist - run: | - python setup.py sdist - - name: Upload sdist - uses: actions/upload-artifact@v3 + - run: python -m pip install build + - name: Build sdist + run: python -m build --sdist + - uses: actions/upload-artifact@v3 with: name: dist path: dist/*.tar.gz @@ -38,10 +37,12 @@ jobs: steps: - name: Check out Google Benchmark uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up QEMU if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 with: platforms: all @@ -61,7 +62,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: dist - path: ./wheelhouse/*.whl + path: wheelhouse/*.whl pypi_upload: name: Publish google-benchmark wheels to PyPI @@ -74,4 +75,4 @@ jobs: with: name: dist path: dist - - uses: pypa/gh-action-pypi-publish@v1.8.10 + - uses: pypa/gh-action-pypi-publish@v1.8.11 diff --git a/pyproject.toml b/pyproject.toml index 92c35066e8..aa24ae8c3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=64", "setuptools-scm[toml]>=8"] +requires = ["setuptools", "setuptools-scm[toml]", "wheel"] build-backend = "setuptools.build_meta" [project] From 6b7e86c5c85095d7a46eaba203d3c4450a445782 Mon Sep 17 00:00:00 2001 From: IS <133409570+iakovs@users.noreply.github.com> Date: Wed, 20 Dec 2023 09:54:55 +0000 Subject: [PATCH 177/561] Fix mis-matching argument in closing tag for cmake macro (#1714) (#1715) Co-authored-by: Iakov Sergeev --- CONTRIBUTORS | 1 + test/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b3d1d58199..9ca2caa3ee 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -56,6 +56,7 @@ Gergő Szitár Hannes Hauswedell Henrique Bucher Ismael Jimenez Martinez +Iakov Sergeev Jern-Kuan Leong JianXiong Zhou Joao Paulo Magalhaes diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d211908432..eb7137efcc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -70,7 +70,7 @@ macro(benchmark_add_test) cmake_parse_arguments(TEST "" "NAME" "" ${ARGN}) set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() -endmacro(compile_output_test) +endmacro(benchmark_add_test) # Demonstration executable compile_benchmark_test(benchmark_test) From 7b52bf7346dead5ef4f29d7f98d2a26d6194252f Mon Sep 17 00:00:00 2001 From: Abhina Sree <69635948+abhina-sree@users.noreply.github.com> Date: Wed, 20 Dec 2023 12:18:37 -0500 Subject: [PATCH 178/561] define HOST_NAME_MAX for z/oS (#1717) --- src/sysinfo.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 8875728266..fb33517090 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -460,6 +460,8 @@ std::string GetSystemName() { #define HOST_NAME_MAX 256 #elif defined(BENCHMARK_OS_SOLARIS) #define HOST_NAME_MAX MAXHOSTNAMELEN +#elif defined(BENCHMARK_OS_ZOS) +#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX #else #pragma message("HOST_NAME_MAX not defined. using 64") #define HOST_NAME_MAX 64 From 3028899d61f2e7832f76de8620504ef3c93a4c53 Mon Sep 17 00:00:00 2001 From: dhmemi Date: Fri, 22 Dec 2023 10:24:23 +0800 Subject: [PATCH 179/561] fix: fail to import gbench in bazel and python3.12 --- tools/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 0e36472801..84d24cf26d 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -13,6 +13,7 @@ py_binary( name = "compare", srcs = ["compare.py"], python_version = "PY3", + imports = ["."], deps = [ ":gbench", ], From 2d2e07e3c5f93f210e77356fb83953fda03673f5 Mon Sep 17 00:00:00 2001 From: Afanasyev Ivan Date: Wed, 3 Jan 2024 19:40:59 +0700 Subject: [PATCH 180/561] Fix division by zero for low frequency timers for CV statistics (#1724) --- src/statistics.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/statistics.cc b/src/statistics.cc index 4a639fd2b9..261dcb299a 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -84,6 +84,8 @@ double StatisticsCV(const std::vector& v) { const auto stddev = StatisticsStdDev(v); const auto mean = StatisticsMean(v); + if (std::fpclassify(mean) == FP_ZERO) return 0.0; + return stddev / mean; } From e523e454f2866e7dc809c29b0c33ac854c74deb8 Mon Sep 17 00:00:00 2001 From: hamptonm1 <79232909+hamptonm1@users.noreply.github.com> Date: Thu, 4 Jan 2024 04:11:07 -0500 Subject: [PATCH 181/561] Update perf_counters_gtest.cc (#1728) --- test/perf_counters_gtest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index 54c78635b8..2e63049285 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -41,7 +41,7 @@ TEST(PerfCountersTest, NegativeTest) { return; } EXPECT_TRUE(PerfCounters::Initialize()); - // Sanity checks + // Safety checks // Create() will always create a valid object, even if passed no or // wrong arguments as the new behavior is to warn and drop unsupported // counters From 99bdb2127d1fa1cff444bbefb814e105c7d20c45 Mon Sep 17 00:00:00 2001 From: aurel32 Date: Thu, 4 Jan 2024 10:16:40 +0100 Subject: [PATCH 182/561] CycleClock: use RDTIME instead of RDCYCLE on RISC-V (#1727) Starting with Linux 6.6 [1], RDCYCLE is a privileged instruction on RISC-V and can't be used directly from userland. There is a sysctl option to change that as a transition period, but it will eventually disappear. Use RDTIME instead, which while less accurate has the advantage of being synchronized between CPU (and thus monotonic) and of constant frequency. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cc4c07c89aada16229084eeb93895c95b7eabaa3 Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/cycleclock.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index dfc7ae72d5..931bba1462 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -189,15 +189,16 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { #endif return tsc; #elif defined(__riscv) // RISC-V - // Use RDCYCLE (and RDCYCLEH on riscv32) + // Use RDTIME (and RDTIMEH on riscv32). + // RDCYCLE is a privileged instruction since Linux 6.6. #if __riscv_xlen == 32 uint32_t cycles_lo, cycles_hi0, cycles_hi1; // This asm also includes the PowerPC overflow handling strategy, as above. // Implemented in assembly because Clang insisted on branching. asm volatile( - "rdcycleh %0\n" - "rdcycle %1\n" - "rdcycleh %2\n" + "rdtimeh %0\n" + "rdtime %1\n" + "rdtimeh %2\n" "sub %0, %0, %2\n" "seqz %0, %0\n" "sub %0, zero, %0\n" @@ -206,7 +207,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { return (static_cast(cycles_hi1) << 32) | cycles_lo; #else uint64_t cycles; - asm volatile("rdcycle %0" : "=r"(cycles)); + asm volatile("rdtime %0" : "=r"(cycles)); return cycles; #endif #elif defined(__e2k__) || defined(__elbrus__) From c213e41eb901ca65bf910d4381c4a07049d794a3 Mon Sep 17 00:00:00 2001 From: Tommy Chiang Date: Thu, 4 Jan 2024 02:50:33 -0800 Subject: [PATCH 183/561] Enable Large-file Support (#1726) * Enable Large-file Support This should fix https://github.com/google/benchmark/issues/1725 * Use whitespaces instead of tab in BUILD.bazel --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- BUILD.bazel | 4 ++++ CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/BUILD.bazel b/BUILD.bazel index 64188344c1..c51cd895c4 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -51,6 +51,10 @@ cc_library( }), defines = [ "BENCHMARK_STATIC_DEFINE", + # Turn on Large-file Support + "_FILE_OFFSET_BITS=64", + "_LARGEFILE64_SOURCE", + "_LARGEFILE_SOURCE", ] + select({ ":perfcounters": ["HAVE_LIBPFM"], "//conditions:default": [], diff --git a/CMakeLists.txt b/CMakeLists.txt index 5757283296..e7bce1577d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,10 @@ if (MSVC) set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG") endif() else() + # Turn on Large-file Support + add_definitions(-D_FILE_OFFSET_BITS=64) + add_definitions(-D_LARGEFILE64_SOURCE) + add_definitions(-D_LARGEFILE_SOURCE) # Turn compiler warnings up to 11 add_cxx_compiler_flag(-Wall) add_cxx_compiler_flag(-Wextra) From e3824e7503187993b287ac8c8144a35bf5ccfd44 Mon Sep 17 00:00:00 2001 From: Abhina Sree <69635948+abhina-sree@users.noreply.github.com> Date: Thu, 4 Jan 2024 06:07:01 -0500 Subject: [PATCH 184/561] fix per-thread timing error on z/OS (#1719) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/timers.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/timers.cc b/src/timers.cc index 84f48bc2ef..667e7b2eef 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -182,6 +182,9 @@ double ThreadCPUUsage() { // RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See // https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c return ProcessCPUUsage(); +#elif defined(BENCHMARK_OS_ZOS) + // z/OS doesn't support CLOCK_THREAD_CPUTIME_ID. + return ProcessCPUUsage(); #elif defined(BENCHMARK_OS_SOLARIS) struct rusage ru; if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru); From e0ec670d20874c3627b583ce45e914235ac3f8a2 Mon Sep 17 00:00:00 2001 From: dhmemi Date: Fri, 5 Jan 2024 11:23:23 +0800 Subject: [PATCH 185/561] style: re-format BUILD file with buildifier. --- tools/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 84d24cf26d..8ef6a86598 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -12,8 +12,8 @@ py_library( py_binary( name = "compare", srcs = ["compare.py"], - python_version = "PY3", imports = ["."], + python_version = "PY3", deps = [ ":gbench", ], From 07c98d5a44908593c7e2fad1ab004aa1c3a234f3 Mon Sep 17 00:00:00 2001 From: Li-Yu Yu Date: Fri, 5 Jan 2024 18:27:12 +0800 Subject: [PATCH 186/561] Avoid leaking LFS flags to reverse dependencies (#1730) Follow up of #1725. `defines` propagates to reverse dependencies, while `local_defines` don't. If we use `defines` then there's risk of ODR violation: Suppose a user have a cc_library foo that depends on bar and benchmark: cc_library(name = "foo", deps = [":bar", "@com_github_google_benchmark//:benchmark"]) And bar has a class that has LFS-dependant ABI: cc_library(name = "foo") class Bar { off_t member; }; Bar would be compiled without LFS, but linked to foo when assuming LFS is enabled. So we limit LFS to within the library only. benchmark does not have LFS dependant public ABIs so it should be fine. --- BUILD.bazel | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index c51cd895c4..0178e2c009 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -51,10 +51,6 @@ cc_library( }), defines = [ "BENCHMARK_STATIC_DEFINE", - # Turn on Large-file Support - "_FILE_OFFSET_BITS=64", - "_LARGEFILE64_SOURCE", - "_LARGEFILE_SOURCE", ] + select({ ":perfcounters": ["HAVE_LIBPFM"], "//conditions:default": [], @@ -67,6 +63,12 @@ cc_library( # Using `defines` (i.e. not `local_defines`) means that no # dependent rules need to bother about defining the macro. linkstatic = True, + local_defines = [ + # Turn on Large-file Support + "_FILE_OFFSET_BITS=64", + "_LARGEFILE64_SOURCE", + "_LARGEFILE_SOURCE", + ], strip_include_prefix = "include", visibility = ["//visibility:public"], deps = select({ From a6b78ef16832e6774e0277495ac628b253c9244a Mon Sep 17 00:00:00 2001 From: FantasqueX Date: Fri, 5 Jan 2024 18:35:20 +0800 Subject: [PATCH 187/561] Change Fixture to use non-const SetUp and TearDown in example (#1723) Const SetUp and TearDown were deprecated in https://github.com/google/benchmark/pull/285 Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- docs/user_guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 2ceb13eb59..95f57b3ec9 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -591,10 +591,10 @@ For Example: ```c++ class MyFixture : public benchmark::Fixture { public: - void SetUp(const ::benchmark::State& state) { + void SetUp(::benchmark::State& state) { } - void TearDown(const ::benchmark::State& state) { + void TearDown(::benchmark::State& state) { } }; From e61e332df951b947e858011449a32c3ed5049db7 Mon Sep 17 00:00:00 2001 From: Benny Tordrup Date: Fri, 5 Jan 2024 15:08:28 +0100 Subject: [PATCH 188/561] Issue1731 created console does not receive output (#1732) * Instead of directly comparing std::cout and GetOutputStream(), the underlying buffers are retreived via rdbuf(), and then compared. * Instead of fflush(stdout), call out.flush(). Use out << FormatString() instead of vprintf --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/colorprint.cc | 6 +++--- src/console_reporter.cc | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/colorprint.cc b/src/colorprint.cc index 0bfd67041d..abc71492f7 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -140,12 +140,12 @@ void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. - fflush(stdout); + out.flush(); SetConsoleTextAttribute(stdout_handle, GetPlatformColorCode(color) | FOREGROUND_INTENSITY); - vprintf(fmt, args); + out << FormatString(fmt, args); - fflush(stdout); + out.flush(); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 10e05e133e..35c3de2a4d 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -42,11 +42,15 @@ bool ConsoleReporter::ReportContext(const Context& context) { PrintBasicContext(&GetErrorStream(), context); #ifdef BENCHMARK_OS_WINDOWS - if ((output_options_ & OO_Color) && &std::cout != &GetOutputStream()) { - GetErrorStream() - << "Color printing is only supported for stdout on windows." - " Disabling color printing\n"; - output_options_ = static_cast(output_options_ & ~OO_Color); + if ((output_options_ & OO_Color)) { + auto stdOutBuf = std::cout.rdbuf(); + auto outStreamBuf = GetOutputStream().rdbuf(); + if (stdOutBuf != outStreamBuf) { + GetErrorStream() + << "Color printing is only supported for stdout on windows." + " Disabling color printing\n"; + output_options_ = static_cast(output_options_ & ~OO_Color); + } } #endif From 96d820f73f01647490782f65f8fb984663575d03 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 8 Jan 2024 12:57:00 +0300 Subject: [PATCH 189/561] tools/compare: don't actually discard valid (but zero) `pvalue` (#1733) * tools/compare: when dumping json, pretty-print it It's rather completely non-human-readable otherwise. I can't imagine the filesize really matters, and if it does, it should just be compressed later on. * tools/compare: add failing test * tools/compare: don't actually discard valid (but zero) `pvalue` So, this is embarressing. For a very large number of repetitions, we can end up with pvalue of a true zero, and it obviously compares false, and we treat it as-if we failed to compute it... --- tools/compare.py | 2 +- tools/gbench/Inputs/test5_run0.json | 18 ++++++ tools/gbench/Inputs/test5_run1.json | 18 ++++++ tools/gbench/report.py | 96 ++++++++++++++++++++++++++++- 4 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 tools/gbench/Inputs/test5_run0.json create mode 100644 tools/gbench/Inputs/test5_run1.json diff --git a/tools/compare.py b/tools/compare.py index 3cc9e5eb4a..7572520cc0 100755 --- a/tools/compare.py +++ b/tools/compare.py @@ -327,7 +327,7 @@ def main(): # Optionally, diff and output to JSON if args.dump_to_json is not None: with open(args.dump_to_json, "w") as f_json: - json.dump(diff_report, f_json) + json.dump(diff_report, f_json, indent=1) class TestParser(unittest.TestCase): diff --git a/tools/gbench/Inputs/test5_run0.json b/tools/gbench/Inputs/test5_run0.json new file mode 100644 index 0000000000..074103b11d --- /dev/null +++ b/tools/gbench/Inputs/test5_run0.json @@ -0,0 +1,18 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_ManyRepetitions", + "iterations": 1000, + "real_time": 1, + "cpu_time": 1000, + "time_unit": "s" + } + ] +} diff --git a/tools/gbench/Inputs/test5_run1.json b/tools/gbench/Inputs/test5_run1.json new file mode 100644 index 0000000000..430df9f0da --- /dev/null +++ b/tools/gbench/Inputs/test5_run1.json @@ -0,0 +1,18 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_ManyRepetitions", + "iterations": 1000, + "real_time": 1000, + "cpu_time": 1, + "time_unit": "s" + } + ] +} diff --git a/tools/gbench/report.py b/tools/gbench/report.py index 10e6b508f0..7158fd1654 100644 --- a/tools/gbench/report.py +++ b/tools/gbench/report.py @@ -315,7 +315,7 @@ def get_difference_report(json1, json2, utest=False): have_optimal_repetitions, cpu_pvalue, time_pvalue = calc_utest( timings_cpu, timings_time ) - if cpu_pvalue and time_pvalue: + if cpu_pvalue is not None and time_pvalue is not None: utest_results = { "have_optimal_repetitions": have_optimal_repetitions, "cpu_pvalue": cpu_pvalue, @@ -1490,6 +1490,100 @@ def test_json_diff_report_pretty_printing(self): self.assertEqual(out["name"], expected) +class TestReportDifferenceWithUTestWhileDisplayingAggregatesOnly2( + unittest.TestCase +): + @classmethod + def setUpClass(cls): + def load_results(): + import json + + testInputs = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "Inputs" + ) + testOutput1 = os.path.join(testInputs, "test5_run0.json") + testOutput2 = os.path.join(testInputs, "test5_run1.json") + with open(testOutput1, "r") as f: + json1 = json.load(f) + json1["benchmarks"] = [ + json1["benchmarks"][0] for i in range(1000) + ] + with open(testOutput2, "r") as f: + json2 = json.load(f) + json2["benchmarks"] = [ + json2["benchmarks"][0] for i in range(1000) + ] + return json1, json2 + + json1, json2 = load_results() + cls.json_diff_report = get_difference_report(json1, json2, utest=True) + + def test_json_diff_report_pretty_printing(self): + expect_line = [ + "BM_ManyRepetitions_pvalue", + "0.0000", + "0.0000", + "U", + "Test,", + "Repetitions:", + "1000", + "vs", + "1000", + ] + output_lines_with_header = print_difference_report( + self.json_diff_report, utest=True, utest_alpha=0.05, use_color=False + ) + output_lines = output_lines_with_header[2:] + found = False + for i in range(0, len(output_lines)): + parts = [x for x in output_lines[i].split(" ") if x] + found = expect_line == parts + if found: + break + self.assertTrue(found) + + def test_json_diff_report(self): + expected_output = [ + { + "name": "BM_ManyRepetitions", + "label": "", + "time_unit": "s", + "run_type": "", + "aggregate_name": "", + "utest": { + "have_optimal_repetitions": True, + "cpu_pvalue": 0.0, + "time_pvalue": 0.0, + "nr_of_repetitions": 1000, + "nr_of_repetitions_other": 1000, + }, + }, + { + "name": "OVERALL_GEOMEAN", + "label": "", + "measurements": [ + { + "real_time": 1.0, + "cpu_time": 1000.000000000069, + "real_time_other": 1000.000000000069, + "cpu_time_other": 1.0, + "time": 999.000000000069, + "cpu": -0.9990000000000001, + } + ], + "time_unit": "s", + "run_type": "aggregate", + "aggregate_name": "geomean", + "utest": {}, + }, + ] + self.assertEqual(len(self.json_diff_report), len(expected_output)) + for out, expected in zip(self.json_diff_report, expected_output): + self.assertEqual(out["name"], expected["name"]) + self.assertEqual(out["time_unit"], expected["time_unit"]) + assert_utest(self, out, expected) + + def assert_utest(unittest_instance, lhs, rhs): if lhs["utest"]: unittest_instance.assertAlmostEqual( From 54e4327190b6c06aeadc3186ed17566fd8da2a61 Mon Sep 17 00:00:00 2001 From: Benny Tordrup Date: Tue, 9 Jan 2024 15:59:10 +0100 Subject: [PATCH 190/561] Issue 1734: Streams not flushed if not running actual benchmarks (#1735) Consistently flush Out and Err streams, otherwise they might not get flushed and the output lost when using custom streams. Fixes #1734. --- src/benchmark.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 6139e59d05..7dd6eaf519 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -577,12 +577,16 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, Err << "A custom file reporter was provided but " "--benchmark_out= was not specified." << std::endl; + Out.flush(); + Err.flush(); std::exit(1); } if (!fname.empty()) { output_file.open(fname); if (!output_file.is_open()) { Err << "invalid file name: '" << fname << "'" << std::endl; + Out.flush(); + Err.flush(); std::exit(1); } if (!file_reporter) { @@ -597,10 +601,16 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, } std::vector benchmarks; - if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) return 0; + if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) { + Out.flush(); + Err.flush(); + return 0; + } if (benchmarks.empty()) { Err << "Failed to match any benchmarks against regex: " << spec << "\n"; + Out.flush(); + Err.flush(); return 0; } @@ -611,6 +621,8 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, internal::RunBenchmarks(benchmarks, display_reporter, file_reporter); } + Out.flush(); + Err.flush(); return benchmarks.size(); } From 882f6f5ae00a117ffb3b2e105eedfe4d411c12ef Mon Sep 17 00:00:00 2001 From: Ananta Bastola Date: Tue, 9 Jan 2024 10:34:42 -0500 Subject: [PATCH 191/561] fix(cmakelists.txt): enforce CMake to find PFM or fail when BENCHMARK_ENABLE_LIBPFM is ON (#1705) Fixes #1702 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7bce1577d..9625c2dc16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,7 +316,7 @@ find_package(Threads REQUIRED) cxx_feature_check(PTHREAD_AFFINITY) if (BENCHMARK_ENABLE_LIBPFM) - find_package(PFM) + find_package(PFM REQUIRED) endif() # Set up directories From ea71a14891474943fc1f34d359f9e0e82476ffe1 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 10 Jan 2024 12:37:39 +0300 Subject: [PATCH 192/561] Docs: `reducing_variance.md`: proofreading, fix typos (#1736) --- docs/reducing_variance.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/reducing_variance.md b/docs/reducing_variance.md index e566ab9852..105f96e769 100644 --- a/docs/reducing_variance.md +++ b/docs/reducing_variance.md @@ -14,8 +14,6 @@ you might want to disable the CPU frequency scaling while running the benchmark, as well as consider other ways to stabilize the performance of your system while benchmarking. -See [Reducing Variance](reducing_variance.md) for more information. - Exactly how to do this depends on the Linux distribution, desktop environment, and installed programs. Specific details are a moving target, so we will not attempt to exhaustively document them here. @@ -67,7 +65,7 @@ program. Reducing sources of variance is OS and architecture dependent, which is one reason some companies maintain machines dedicated to performance testing. -Some of the easier and and effective ways of reducing variance on a typical +Some of the easier and effective ways of reducing variance on a typical Linux workstation are: 1. Use the performance governor as [discussed @@ -89,7 +87,7 @@ above](user_guide#disabling-cpu-frequency-scaling). 4. Close other programs that do non-trivial things based on timers, such as your web browser, desktop environment, etc. 5. Reduce the working set of your benchmark to fit within the L1 cache, but - do be aware that this may lead you to optimize for an unrelistic + do be aware that this may lead you to optimize for an unrealistic situation. Further resources on this topic: From 3d293cd67a264701378c46e2ae3b6408d533e093 Mon Sep 17 00:00:00 2001 From: Aleksey <778977+Arech@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:28:04 +0300 Subject: [PATCH 193/561] Fix C-style typecasting in QNX-specific code (#1739) C-style typecasting breaks the build due to `-Werror=old-style-cast` which should remain in place. --- src/sysinfo.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index fb33517090..04d64dc5b6 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -777,8 +777,9 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { kstat_close(kc); return clock_hz; #elif defined(BENCHMARK_OS_QNX) - return static_cast((int64_t)(SYSPAGE_ENTRY(cpuinfo)->speed) * - (int64_t)(1000 * 1000)); + return static_cast( + static_cast(SYSPAGE_ENTRY(cpuinfo)->speed) * + static_cast(1000 * 1000)); #elif defined(BENCHMARK_OS_QURT) // QuRT doesn't provide any API to query Hexagon frequency. return 1000000000; From 4682db08bc7bb7e547e0a1056e32392998f8101f Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Thu, 18 Jan 2024 14:35:57 +0100 Subject: [PATCH 194/561] Bump pre-commit dependencies (#1740) Also fix a mypy error in `tools.gbench.util` - the condition behaves the same as before, but in the new mypy version, the old condition results in an unreachable code error for the final `return False` statement. This is most likely a bug in mypy's reachability analysis, but the fix is easy enough here to circumvent it. --- .pre-commit-config.yaml | 4 ++-- tools/gbench/util.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a58a5cff0d..0247d1b062 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,13 +5,13 @@ repos: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.7.1 + rev: v1.8.0 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.7 + rev: v0.1.13 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 84747d1053..d49018a59e 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -131,9 +131,7 @@ def benchmark_wanted(benchmark): if benchmark_filter is None: return True name = benchmark.get("run_name", None) or benchmark["name"] - if re.search(benchmark_filter, name): - return True - return False + return re.search(benchmark_filter, name) is not None with open(fname, "r") as f: results = json.load(f) From faef450eb9ba58065360d1000ceb03b8d583f366 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 29 Jan 2024 13:02:29 +0000 Subject: [PATCH 195/561] changes to run bazel migration scripts part of #1743 --- MODULE.bazel | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index cdac6c899c..7e0e016123 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,9 +4,9 @@ module( ) bazel_dep(name = "bazel_skylib", version = "1.5.0") -bazel_dep(name = "platforms", version = "0.0.6") +bazel_dep(name = "platforms", version = "0.0.7") bazel_dep(name = "rules_foreign_cc", version = "0.10.1") -bazel_dep(name = "rules_cc", version = "0.0.6") +bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_python", version = "0.27.1", dev_dependency = True) bazel_dep(name = "googletest", version = "1.12.1", dev_dependency = True, repo_name = "com_google_googletest") @@ -28,3 +28,5 @@ pip.parse( requirements_lock = "//tools:requirements.txt", ) use_repo(pip, "tools_pip_deps") + +# -- bazel_dep definitions -- # From 8e2d258644aeaa13ba441f27e053dd05656517a5 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 29 Jan 2024 13:06:57 +0000 Subject: [PATCH 196/561] ignore new bzlmod lock file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 704f56c257..24a1fb6d74 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ rules.ninja # bazel output symlinks. bazel-* +MODULE.bazel.lock # out-of-source build top-level folders. build/ From 17bc235ab31aa48b9a7e7c444b6b4f4c22e4be39 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 29 Jan 2024 16:15:43 +0300 Subject: [PATCH 197/561] Output library / schema versions in JSON context block (#1742) * CMake: `get_git_version()`: just use `--dirty` flag of `git describe` * CMake: move version normalization out of `get_git_version()` Mainly, i want `get_git_version()` to return true version, not something sanitized. * JSON reporter: store library version and schema version in `context` * Tools: discard inputs with unexpected `json_schema_version` * Extract version string into `GetBenchmarkVersiom()` --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- CMakeLists.txt | 18 ++++++++++++++---- cmake/GetGitVersion.cmake | 30 ++++-------------------------- include/benchmark/benchmark.h | 3 +++ src/CMakeLists.txt | 7 +++++++ src/benchmark.cc | 8 ++++++++ src/json_reporter.cc | 7 +++++++ test/reporter_output_test.cc | 3 +++ tools/gbench/util.py | 9 +++++++++ 8 files changed, 55 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9625c2dc16..d9bcc6a493 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,16 +105,26 @@ get_git_version(GIT_VERSION) # If no git version can be determined, use the version # from the project() command if ("${GIT_VERSION}" STREQUAL "0.0.0") - set(VERSION "${benchmark_VERSION}") + set(VERSION "v${benchmark_VERSION}") else() set(VERSION "${GIT_VERSION}") endif() + +# Normalize version: drop "v" prefix, replace first "-" with ".", +# drop everything after second "-" (including said "-"). +string(STRIP ${VERSION} VERSION) +if(VERSION MATCHES v[^-]*-) + string(REGEX REPLACE "v([^-]*)-([0-9]+)-.*" "\\1.\\2" NORMALIZED_VERSION ${VERSION}) +else() + string(REGEX REPLACE "v(.*)" "\\1" NORMALIZED_VERSION ${VERSION}) +endif() + # Tell the user what versions we are using -message(STATUS "Google Benchmark version: ${VERSION}") +message(STATUS "Google Benchmark version: ${VERSION}, normalized to ${NORMALIZED_VERSION}") # The version of the libraries -set(GENERIC_LIB_VERSION ${VERSION}) -string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION) +set(GENERIC_LIB_VERSION ${NORMALIZED_VERSION}) +string(SUBSTRING ${NORMALIZED_VERSION} 0 1 GENERIC_LIB_SOVERSION) # Import our CMake modules include(AddCXXCompilerFlag) diff --git a/cmake/GetGitVersion.cmake b/cmake/GetGitVersion.cmake index 04a1f9b70d..b0210103b2 100644 --- a/cmake/GetGitVersion.cmake +++ b/cmake/GetGitVersion.cmake @@ -20,38 +20,16 @@ set(__get_git_version INCLUDED) function(get_git_version var) if(GIT_EXECUTABLE) - execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8 + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8 --dirty WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE status - OUTPUT_VARIABLE GIT_DESCRIBE_VERSION + OUTPUT_VARIABLE GIT_VERSION ERROR_QUIET) if(status) - set(GIT_DESCRIBE_VERSION "v0.0.0") + set(GIT_VERSION "v0.0.0") endif() - - string(STRIP ${GIT_DESCRIBE_VERSION} GIT_DESCRIBE_VERSION) - if(GIT_DESCRIBE_VERSION MATCHES v[^-]*-) - string(REGEX REPLACE "v([^-]*)-([0-9]+)-.*" "\\1.\\2" GIT_VERSION ${GIT_DESCRIBE_VERSION}) - else() - string(REGEX REPLACE "v(.*)" "\\1" GIT_VERSION ${GIT_DESCRIBE_VERSION}) - endif() - - # Work out if the repository is dirty - execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_QUIET - ERROR_QUIET) - execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD -- - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE GIT_DIFF_INDEX - ERROR_QUIET) - string(COMPARE NOTEQUAL "${GIT_DIFF_INDEX}" "" GIT_DIRTY) - if (${GIT_DIRTY}) - set(GIT_DESCRIBE_VERSION "${GIT_DESCRIBE_VERSION}-dirty") - endif() - message(STATUS "git version: ${GIT_DESCRIBE_VERSION} normalized to ${GIT_VERSION}") else() - set(GIT_VERSION "0.0.0") + set(GIT_VERSION "v0.0.0") endif() set(${var} ${GIT_VERSION} PARENT_SCOPE) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 9849c4287a..25c3eef70f 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -302,6 +302,9 @@ class BenchmarkReporter; // Default number of minimum benchmark running time in seconds. const char kDefaultMinTimeStr[] = "0.5s"; +// Returns the version of the library. +BENCHMARK_EXPORT std::string GetBenchmarkVersiom(); + BENCHMARK_EXPORT void PrintDefaultHelp(); BENCHMARK_EXPORT void Initialize(int* argc, char** argv, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index daf82fb131..943594b70b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,13 @@ target_include_directories(benchmark PUBLIC $ ) +set_property( + SOURCE benchmark.cc + APPEND + PROPERTY COMPILE_DEFINITIONS + BENCHMARK_VERSION="${VERSION}" +) + # libpfm, if available if (PFM_FOUND) target_link_libraries(benchmark PRIVATE PFM::libpfm) diff --git a/src/benchmark.cc b/src/benchmark.cc index 7dd6eaf519..489c8a0a4f 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -748,6 +748,14 @@ int InitializeStreams() { } // end namespace internal +std::string GetBenchmarkVersiom() { +#if defined(BENCHMARK_VERSION) + return {BENCHMARK_VERSION}; +#else + return "hello, bazel!"; +#endif +} + void PrintDefaultHelp() { fprintf(stdout, "benchmark" diff --git a/src/json_reporter.cc b/src/json_reporter.cc index 6559dfd5e6..0202c64a0e 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -167,12 +167,19 @@ bool JSONReporter::ReportContext(const Context& context) { } out << "],\n"; + out << indent << FormatKV("library_version", GetBenchmarkVersiom()); + out << ",\n"; + #if defined(NDEBUG) const char build_type[] = "release"; #else const char build_type[] = "debug"; #endif out << indent << FormatKV("library_build_type", build_type); + out << ",\n"; + + // NOTE: our json schema is not strictly tied to the library version! + out << indent << FormatKV("json_schema_version", int64_t(1)); std::map* global_context = internal::GetGlobalContext(); diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 657a9a1079..ea5381d20b 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -55,6 +55,9 @@ static int AddContextCases() { {{"Load Average: (%float, ){0,2}%float$", MR_Next}}); } AddCases(TC_JSONOut, {{"\"load_avg\": \\[(%float,?){0,3}],$", MR_Next}}); + AddCases(TC_JSONOut, {{"\"library_version\": \".*\",$", MR_Next}}); + AddCases(TC_JSONOut, {{"\"library_build_type\": \".*\",$", MR_Next}}); + AddCases(TC_JSONOut, {{"\"json_schema_version\": 1$", MR_Next}}); return 0; } int dummy_register = AddContextCases(); diff --git a/tools/gbench/util.py b/tools/gbench/util.py index d49018a59e..4d061a3a1e 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -135,6 +135,15 @@ def benchmark_wanted(benchmark): with open(fname, "r") as f: results = json.load(f) + if "context" in results: + if "json_schema_version" in results["context"]: + json_schema_version = results["context"]["json_schema_version"] + if json_schema_version != 1: + print( + "In %s, got unnsupported JSON schema version: %i, expected 1" + % (fname, json_schema_version) + ) + sys.exit(1) if "benchmarks" in results: results["benchmarks"] = list( filter(benchmark_wanted, results["benchmarks"]) From 30a37e1b0bfbec07bbb44f8cac8c162ef9f5f9ed Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:48:04 +0000 Subject: [PATCH 198/561] set library version in bazel (#1746) * set library version in bazel --- BUILD.bazel | 1 + src/benchmark.cc | 8 +------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 0178e2c009..d72ae86728 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -51,6 +51,7 @@ cc_library( }), defines = [ "BENCHMARK_STATIC_DEFINE", + "BENCHMARK_VERSION=\\\"" + (module_version() if module_version() != None else "") + "\\\"", ] + select({ ":perfcounters": ["HAVE_LIBPFM"], "//conditions:default": [], diff --git a/src/benchmark.cc b/src/benchmark.cc index 489c8a0a4f..8ec30c88c0 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -748,13 +748,7 @@ int InitializeStreams() { } // end namespace internal -std::string GetBenchmarkVersiom() { -#if defined(BENCHMARK_VERSION) - return {BENCHMARK_VERSION}; -#else - return "hello, bazel!"; -#endif -} +std::string GetBenchmarkVersiom() { return {BENCHMARK_VERSION}; } void PrintDefaultHelp() { fprintf(stdout, From e990563876ef92990e873dc5b479d3b79cda2547 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 30 Jan 2024 15:44:36 +0300 Subject: [PATCH 199/561] Add `BENCHMARK_TEMPLATE[12]_CAPTURE`, fusion of `BENCHMARK_CAPTURE` and `BENCHMARK_TEMPLATE` (#1747) Test coverage isn't great, but not worse than the existing one. You'd think `BENCHMARK_CAPTURE` would suffice, but you can't pass `func` to it (due to the `<` and `>`), and when passing `(func)` we get issues with brackets. So i'm not sure if we can fully avoid this helper. That being said, if there is only a single template argument, `BENCHMARK_CAPTURE()` works fine if we avoid using function name. --- docs/user_guide.md | 26 ++++++++++++++++++++++++++ include/benchmark/benchmark.h | 27 ++++++++++++++++++++++++++- test/benchmark_test.cc | 26 ++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 95f57b3ec9..d22a906909 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -28,6 +28,8 @@ [Templated Benchmarks](#templated-benchmarks) +[Templated Benchmarks that take arguments](#templated-benchmarks-with-arguments) + [Fixtures](#fixtures) [Custom Counters](#custom-counters) @@ -574,6 +576,30 @@ Three macros are provided for adding benchmark templates. #define BENCHMARK_TEMPLATE2(func, arg1, arg2) ``` + + +## Templated Benchmarks that take arguments + +Sometimes there is a need to template benchmarks, and provide arguments to them. + +```c++ +template void BM_Sequential_With_Step(benchmark::State& state, int step) { + Q q; + typename Q::value_type v; + for (auto _ : state) { + for (int i = state.range(0); i-=step; ) + q.push(v); + for (int e = state.range(0); e-=step; ) + q.Wait(&v); + } + // actually messages, not bytes: + state.SetBytesProcessed( + static_cast(state.iterations())*state.range(0)); +} + +BENCHMARK_TEMPLATE1_CAPTURE(BM_Sequential, WaitQueue, Step1, 1)->Range(1<<0, 1<<10); +``` + ## Fixtures diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 25c3eef70f..5a1eef89e4 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1523,7 +1523,7 @@ class Fixture : public internal::Benchmark { // /* Registers a benchmark named "BM_takes_args/int_string_test` */ // BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); #define BENCHMARK_CAPTURE(func, test_case_name, ...) \ - BENCHMARK_PRIVATE_DECLARE(func) = \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ new ::benchmark::internal::FunctionBenchmark( \ #func "/" #test_case_name, \ @@ -1560,6 +1560,31 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_TEMPLATE(n, a) BENCHMARK_TEMPLATE1(n, a) #endif +#ifdef BENCHMARK_HAS_CXX11 +// This will register a benchmark for a templatized function, +// with the additional arguments specified by `...`. +// +// For example: +// +// template ` +// void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) { +// [...] +//} +// /* Registers a benchmark named "BM_takes_args/int_string_test` */ +// BENCHMARK_TEMPLATE1_CAPTURE(BM_takes_args, void, int_string_test, 42, +// std::string("abc")); +#define BENCHMARK_TEMPLATE1_CAPTURE(func, a, test_case_name, ...) \ + BENCHMARK_CAPTURE(func, test_case_name, __VA_ARGS__) + +#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(func) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark( \ + #func "<" #a "," #b ">" \ + "/" #test_case_name, \ + [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) +#endif // BENCHMARK_HAS_CXX11 + #define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ class BaseClass##_##Method##_Benchmark : public BaseClass { \ public: \ diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index 94590d5e41..8b14017d03 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -226,6 +227,31 @@ void BM_non_template_args(benchmark::State& state, int, double) { } BENCHMARK_CAPTURE(BM_non_template_args, basic_test, 0, 0); +template +void BM_template2_capture(benchmark::State& state, ExtraArgs&&... extra_args) { + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + unsigned int dummy[sizeof...(ExtraArgs)] = {extra_args...}; + assert(dummy[0] == 42); + for (auto _ : state) { + } +} +BENCHMARK_TEMPLATE2_CAPTURE(BM_template2_capture, void, char*, foo, 42U); +BENCHMARK_CAPTURE((BM_template2_capture), foo, 42U); + +template +void BM_template1_capture(benchmark::State& state, ExtraArgs&&... extra_args) { + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + unsigned long dummy[sizeof...(ExtraArgs)] = {extra_args...}; + assert(dummy[0] == 24); + for (auto _ : state) { + } +} +BENCHMARK_TEMPLATE1_CAPTURE(BM_template1_capture, void, foo, 24UL); +BENCHMARK_CAPTURE(BM_template1_capture, foo, 24UL); + #endif // BENCHMARK_HAS_CXX11 static void BM_DenseThreadRanges(benchmark::State& st) { From b04cec1bf90c3d8e47739bb3271607a18d8b5106 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Fri, 2 Feb 2024 18:39:46 +0300 Subject: [PATCH 200/561] Deflake CI (#1751) * `complexity_test`: deflake, same as https://github.com/google/benchmark/issues/272 As it can be seen in e.g. https://github.com/google/benchmark/actions/runs/7711328637/job/21016492361 We may get `65: BM_Complexity_O1_BigO 0.00 N^2 0.00 N^2 ` * `user_counters_tabular_test`: deflake We were still getting zero times there. Perhaps this is better? --- test/complexity_test.cc | 2 +- test/user_counters_tabular_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 1248a535fd..1c746afb43 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -88,7 +88,7 @@ const char *enum_big_o_1 = "\\([0-9]+\\)"; // FIXME: Tolerate both '(1)' and 'lgN' as output when the complexity is auto // deduced. // See https://github.com/google/benchmark/issues/272 -const char *auto_big_o_1 = "(\\([0-9]+\\))|(lgN)"; +const char *auto_big_o_1 = "(\\([0-9]+\\))|(lgN)|(N\\^2)"; const char *lambda_big_o_1 = "f\\(N\\)"; // Add enum tests diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index e7ada657b2..3e8fb1bf00 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -372,7 +372,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Tabular/repeats:2/threads:2$", void BM_CounterRates_Tabular(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; From b7ad5e04972d3bd64ca6a79c931c88848b33e588 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 12 Feb 2024 17:56:58 +0100 Subject: [PATCH 201/561] fix typo in GetBenchmarkVersion() (#1755) --- include/benchmark/benchmark.h | 2 +- src/benchmark.cc | 2 +- src/json_reporter.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 5a1eef89e4..c9c1c4bab1 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -303,7 +303,7 @@ class BenchmarkReporter; const char kDefaultMinTimeStr[] = "0.5s"; // Returns the version of the library. -BENCHMARK_EXPORT std::string GetBenchmarkVersiom(); +BENCHMARK_EXPORT std::string GetBenchmarkVersion(); BENCHMARK_EXPORT void PrintDefaultHelp(); diff --git a/src/benchmark.cc b/src/benchmark.cc index 8ec30c88c0..31f2cde8ff 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -748,7 +748,7 @@ int InitializeStreams() { } // end namespace internal -std::string GetBenchmarkVersiom() { return {BENCHMARK_VERSION}; } +std::string GetBenchmarkVersion() { return {BENCHMARK_VERSION}; } void PrintDefaultHelp() { fprintf(stdout, diff --git a/src/json_reporter.cc b/src/json_reporter.cc index 0202c64a0e..b8c8c94c08 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -167,7 +167,7 @@ bool JSONReporter::ReportContext(const Context& context) { } out << "],\n"; - out << indent << FormatKV("library_version", GetBenchmarkVersiom()); + out << indent << FormatKV("library_version", GetBenchmarkVersion()); out << ",\n"; #if defined(NDEBUG) From 385033bd11996db066357b85b00f27005d0e87a5 Mon Sep 17 00:00:00 2001 From: Sam James Date: Tue, 13 Feb 2024 21:04:44 +0000 Subject: [PATCH 202/561] CycleClock: Add support for Alpha architecture (#1753) * Add support for Alpha architecture As documented, the real cycle counter is unsafe to use here, because it is a 32-bit integer which wraps every ~4s. Use gettimeofday instead, which has a limitation of a low-precision real-time-clock (~1ms), but no wrapping. Passes test suite. Support parsing /proc/cpuinfo on Alpha tabular_test: add a missing DoNotOptimize call --- src/cycleclock.h | 9 +++++++++ src/sysinfo.cc | 4 ++++ test/user_counters_tabular_test.cc | 3 +++ 3 files changed, 16 insertions(+) diff --git a/src/cycleclock.h b/src/cycleclock.h index 931bba1462..eff563e7fa 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -218,6 +218,15 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { uint64_t pcycle; asm volatile("%0 = C15:14" : "=r"(pcycle)); return static_cast(pcycle); +#elif defined(__alpha__) + // Alpha has a cycle counter, the PCC register, but it is an unsigned 32-bit + // integer and thus wraps every ~4s, making using it for tick counts + // unreliable beyond this time range. The real-time clock is low-precision, + // roughtly ~1ms, but it is the only option that can reasonable count + // indefinitely. + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; #else // The soft failover to a generic implementation is automatic only for ARM. // For other platforms the developer is expected to make an attempt to create diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 04d64dc5b6..786bb1b413 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -513,7 +513,11 @@ int GetNumCPUs() { std::cerr << "failed to open /proc/cpuinfo\n"; return -1; } +#if defined(__alpha__) + const std::string Key = "cpus detected"; +#else const std::string Key = "processor"; +#endif std::string ln; while (std::getline(f, ln)) { if (ln.empty()) continue; diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index 3e8fb1bf00..ffd3c0992c 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -63,6 +63,9 @@ ADD_CASES(TC_CSVOut, {{"%csv_header," void BM_Counters_Tabular(benchmark::State& state) { for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; state.counters.insert({ From 7f7c96a26497a380b63259be928bbe29394ef2ae Mon Sep 17 00:00:00 2001 From: Sam James Date: Wed, 14 Feb 2024 17:19:46 +0000 Subject: [PATCH 203/561] sysinfo.cc: Always abort on GetNumCPUs failure (#1756) Defines a wrapper function, CheckNumCPUs, which enforces that GetNumCPUs never returns fewer than one CPU. There is no reasonable way to continue if we are unable to identify the number of CPUs. Signed-off-by: Sam James --- src/sysinfo.cc | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 786bb1b413..daeb98b026 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -474,12 +474,11 @@ std::string GetSystemName() { #endif // Catch-all POSIX block. } -int GetNumCPUs() { +int GetNumCPUsImpl() { #ifdef BENCHMARK_HAS_SYSCTL int num_cpu = -1; if (GetSysctl("hw.ncpu", &num_cpu)) return num_cpu; - fprintf(stderr, "Err: %s\n", strerror(errno)); - std::exit(EXIT_FAILURE); + PrintErrorAndDie("Err: ", strerror(errno)); #elif defined(BENCHMARK_OS_WINDOWS) SYSTEM_INFO sysinfo; // Use memset as opposed to = {} to avoid GCC missing initializer false @@ -493,8 +492,8 @@ int GetNumCPUs() { // Returns -1 in case of a failure. long num_cpu = sysconf(_SC_NPROCESSORS_ONLN); if (num_cpu < 0) { - fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n", - strerror(errno)); + PrintErrorAndDie("sysconf(_SC_NPROCESSORS_ONLN) failed with error: ", + strerror(errno)); } return (int)num_cpu; #elif defined(BENCHMARK_OS_QNX) @@ -510,8 +509,7 @@ int GetNumCPUs() { int max_id = -1; std::ifstream f("/proc/cpuinfo"); if (!f.is_open()) { - std::cerr << "failed to open /proc/cpuinfo\n"; - return -1; + PrintErrorAndDie("Failed to open /proc/cpuinfo"); } #if defined(__alpha__) const std::string Key = "cpus detected"; @@ -540,12 +538,10 @@ int GetNumCPUs() { } } if (f.bad()) { - std::cerr << "Failure reading /proc/cpuinfo\n"; - return -1; + PrintErrorAndDie("Failure reading /proc/cpuinfo"); } if (!f.eof()) { - std::cerr << "Failed to read to end of /proc/cpuinfo\n"; - return -1; + PrintErrorAndDie("Failed to read to end of /proc/cpuinfo"); } f.close(); @@ -559,6 +555,16 @@ int GetNumCPUs() { BENCHMARK_UNREACHABLE(); } +int GetNumCPUs() { + const int num_cpus = GetNumCPUsImpl(); + if (num_cpus < 1) { + PrintErrorAndDie( + "Unable to extract number of CPUs. If your platform uses " + "/proc/cpuinfo, custom support may need to be added."); + } + return num_cpus; +} + class ThreadAffinityGuard final { public: ThreadAffinityGuard() : reset_affinity(SetAffinity()) { From 3d85343d65832d05b4dcd6666640e0e38b981c33 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 19 Feb 2024 18:22:35 +0300 Subject: [PATCH 204/561] Rewrite complexity_test to use (hardcoded) manual time (#1757) * Rewrite complexity_test to use (hardcoded) manual time This test is fundamentally flaky, because it tried to read tea leafs, and is inherently misbehaving in CI environments, since there are unmitigated sources of noise. That being said, the computed Big-O also depends on the `--benchmark_min_time=` Fixes https://github.com/google/benchmark/issues/272 * Correctly compute Big-O for manual timings. Fixes #1758. * complexity_test: do more stuff in empty loop * Make all empty loops be a bit longer empty Looks like on windows, some of these tests still fail, i guess clock precision is too small. --- include/benchmark/benchmark.h | 5 + src/benchmark_runner.cc | 1 + src/complexity.cc | 15 ++- test/BUILD | 1 + test/CMakeLists.txt | 8 +- test/basic_test.cc | 2 +- test/complexity_test.cc | 158 ++++++++++++++++++----------- test/diagnostics_test.cc | 4 +- test/link_main_test.cc | 2 +- test/memory_manager_test.cc | 2 +- test/perf_counters_test.cc | 2 +- test/reporter_output_test.cc | 6 +- test/skip_with_error_test.cc | 2 +- test/user_counters_tabular_test.cc | 2 +- test/user_counters_test.cc | 14 +-- 15 files changed, 139 insertions(+), 85 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index c9c1c4bab1..08cfe29da3 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1792,6 +1792,7 @@ class BENCHMARK_EXPORT BenchmarkReporter { real_accumulated_time(0), cpu_accumulated_time(0), max_heapbytes_used(0), + use_real_time_for_initial_big_o(false), complexity(oNone), complexity_lambda(), complexity_n(0), @@ -1834,6 +1835,10 @@ class BENCHMARK_EXPORT BenchmarkReporter { // This is set to 0.0 if memory tracing is not enabled. double max_heapbytes_used; + // By default Big-O is computed for CPU time, but that is not what you want + // to happen when manual time was requested, which is stored as real time. + bool use_real_time_for_initial_big_o; + // Keep track of arguments to compute asymptotic complexity BigO complexity; BigOFunc* complexity_lambda; diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index d35bc30d49..dcddb437e3 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -96,6 +96,7 @@ BenchmarkReporter::Run CreateRunReport( } else { report.real_accumulated_time = results.real_time_used; } + report.use_real_time_for_initial_big_o = b.use_manual_time(); report.cpu_accumulated_time = results.cpu_time_used; report.complexity_n = results.complexity_n; report.complexity = b.complexity(); diff --git a/src/complexity.cc b/src/complexity.cc index e53dd342d1..eee3122646 100644 --- a/src/complexity.cc +++ b/src/complexity.cc @@ -186,8 +186,19 @@ std::vector ComputeBigO( result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity_lambda); result_real = MinimalLeastSq(n, real_time, reports[0].complexity_lambda); } else { - result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity); - result_real = MinimalLeastSq(n, real_time, result_cpu.complexity); + const BigO* InitialBigO = &reports[0].complexity; + const bool use_real_time_for_initial_big_o = + reports[0].use_real_time_for_initial_big_o; + if (use_real_time_for_initial_big_o) { + result_real = MinimalLeastSq(n, real_time, *InitialBigO); + InitialBigO = &result_real.complexity; + // The Big-O complexity for CPU time must have the same Big-O function! + } + result_cpu = MinimalLeastSq(n, cpu_time, *InitialBigO); + InitialBigO = &result_cpu.complexity; + if (!use_real_time_for_initial_big_o) { + result_real = MinimalLeastSq(n, real_time, *InitialBigO); + } } // Drop the 'args' when reporting complexity. diff --git a/test/BUILD b/test/BUILD index 22b7dba4b9..e43b802350 100644 --- a/test/BUILD +++ b/test/BUILD @@ -35,6 +35,7 @@ PER_SRC_TEST_ARGS = { "repetitions_test.cc": [" --benchmark_repetitions=3"], "spec_arg_test.cc": ["--benchmark_filter=BM_NotChosen"], "spec_arg_verbosity_test.cc": ["--v=42"], + "complexity_test.cc": ["--benchmark_min_time=1000000x"], } cc_library( diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eb7137efcc..1de175f98d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -218,14 +218,8 @@ if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) benchmark_add_test(NAME cxx03 COMMAND cxx03_test --benchmark_min_time=0.01s) endif() -# Attempt to work around flaky test failures when running on Appveyor servers. -if (DEFINED ENV{APPVEYOR}) - set(COMPLEXITY_MIN_TIME "0.5s") -else() - set(COMPLEXITY_MIN_TIME "0.01s") -endif() compile_output_test(complexity_test) -benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=${COMPLEXITY_MIN_TIME}) +benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=1000000x) ############################################################################### # GoogleTest Unit Tests diff --git a/test/basic_test.cc b/test/basic_test.cc index cba1b0f992..c25bec7ddd 100644 --- a/test/basic_test.cc +++ b/test/basic_test.cc @@ -5,7 +5,7 @@ void BM_empty(benchmark::State& state) { for (auto _ : state) { - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } } diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 1c746afb43..0c159cd27d 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -69,35 +69,44 @@ int AddComplexityTest(const std::string &test_name, void BM_Complexity_O1(benchmark::State &state) { for (auto _ : state) { - for (int i = 0; i < 1024; ++i) { - benchmark::DoNotOptimize(i); + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + double tmp = state.iterations(); + benchmark::DoNotOptimize(tmp); + for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { + benchmark::DoNotOptimize(state.iterations()); + tmp *= state.iterations(); + benchmark::DoNotOptimize(tmp); } + + // always 1ns per iteration + state.SetIterationTime(42 * 1e-9); } state.SetComplexityN(state.range(0)); } -BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(benchmark::o1); -BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(); BENCHMARK(BM_Complexity_O1) ->Range(1, 1 << 18) + ->UseManualTime() + ->Complexity(benchmark::o1); +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->UseManualTime()->Complexity(); +BENCHMARK(BM_Complexity_O1) + ->Range(1, 1 << 18) + ->UseManualTime() ->Complexity([](benchmark::IterationCount) { return 1.0; }); -const char *one_test_name = "BM_Complexity_O1"; -const char *big_o_1_test_name = "BM_Complexity_O1_BigO"; -const char *rms_o_1_test_name = "BM_Complexity_O1_RMS"; -const char *enum_big_o_1 = "\\([0-9]+\\)"; -// FIXME: Tolerate both '(1)' and 'lgN' as output when the complexity is auto -// deduced. -// See https://github.com/google/benchmark/issues/272 -const char *auto_big_o_1 = "(\\([0-9]+\\))|(lgN)|(N\\^2)"; +const char *one_test_name = "BM_Complexity_O1/manual_time"; +const char *big_o_1_test_name = "BM_Complexity_O1/manual_time_BigO"; +const char *rms_o_1_test_name = "BM_Complexity_O1/manual_time_RMS"; +const char *enum_auto_big_o_1 = "\\([0-9]+\\)"; const char *lambda_big_o_1 = "f\\(N\\)"; // Add enum tests ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, - enum_big_o_1, /*family_index=*/0); + enum_auto_big_o_1, /*family_index=*/0); -// Add auto enum tests +// Add auto tests ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, - auto_big_o_1, /*family_index=*/1); + enum_auto_big_o_1, /*family_index=*/1); // Add lambda tests ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, @@ -107,43 +116,44 @@ ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, // --------------------------- Testing BigO O(N) --------------------------- // // ========================================================================= // -std::vector ConstructRandomVector(int64_t size) { - std::vector v; - v.reserve(static_cast(size)); - for (int i = 0; i < size; ++i) { - v.push_back(static_cast(std::rand() % size)); - } - return v; -} - void BM_Complexity_O_N(benchmark::State &state) { - auto v = ConstructRandomVector(state.range(0)); - // Test worst case scenario (item not in vector) - const int64_t item_not_in_vector = state.range(0) * 2; for (auto _ : state) { - auto it = std::find(v.begin(), v.end(), item_not_in_vector); - benchmark::DoNotOptimize(it); + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + double tmp = state.iterations(); + benchmark::DoNotOptimize(tmp); + for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { + benchmark::DoNotOptimize(state.iterations()); + tmp *= state.iterations(); + benchmark::DoNotOptimize(tmp); + } + + // 1ns per iteration per entry + state.SetIterationTime(state.range(0) * 42 * 1e-9); } state.SetComplexityN(state.range(0)); } BENCHMARK(BM_Complexity_O_N) ->RangeMultiplier(2) - ->Range(1 << 10, 1 << 16) + ->Range(1 << 10, 1 << 20) + ->UseManualTime() ->Complexity(benchmark::oN); BENCHMARK(BM_Complexity_O_N) ->RangeMultiplier(2) - ->Range(1 << 10, 1 << 16) + ->Range(1 << 10, 1 << 20) + ->UseManualTime() + ->Complexity(); +BENCHMARK(BM_Complexity_O_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 20) + ->UseManualTime() ->Complexity([](benchmark::IterationCount n) -> double { return static_cast(n); }); -BENCHMARK(BM_Complexity_O_N) - ->RangeMultiplier(2) - ->Range(1 << 10, 1 << 16) - ->Complexity(); -const char *n_test_name = "BM_Complexity_O_N"; -const char *big_o_n_test_name = "BM_Complexity_O_N_BigO"; -const char *rms_o_n_test_name = "BM_Complexity_O_N_RMS"; +const char *n_test_name = "BM_Complexity_O_N/manual_time"; +const char *big_o_n_test_name = "BM_Complexity_O_N/manual_time_BigO"; +const char *rms_o_n_test_name = "BM_Complexity_O_N/manual_time_RMS"; const char *enum_auto_big_o_n = "N"; const char *lambda_big_o_n = "f\\(N\\)"; @@ -151,40 +161,57 @@ const char *lambda_big_o_n = "f\\(N\\)"; ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name, enum_auto_big_o_n, /*family_index=*/3); +// Add auto tests +ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name, + enum_auto_big_o_n, /*family_index=*/4); + // Add lambda tests ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name, - lambda_big_o_n, /*family_index=*/4); + lambda_big_o_n, /*family_index=*/5); // ========================================================================= // -// ------------------------- Testing BigO O(N*lgN) ------------------------- // +// ------------------------- Testing BigO O(NlgN) ------------------------- // // ========================================================================= // +static const double kLog2E = 1.44269504088896340736; static void BM_Complexity_O_N_log_N(benchmark::State &state) { - auto v = ConstructRandomVector(state.range(0)); for (auto _ : state) { - std::sort(v.begin(), v.end()); + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + double tmp = state.iterations(); + benchmark::DoNotOptimize(tmp); + for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { + benchmark::DoNotOptimize(state.iterations()); + tmp *= state.iterations(); + benchmark::DoNotOptimize(tmp); + } + + state.SetIterationTime(state.range(0) * kLog2E * std::log(state.range(0)) * + 42 * 1e-9); } state.SetComplexityN(state.range(0)); } -static const double kLog2E = 1.44269504088896340736; BENCHMARK(BM_Complexity_O_N_log_N) ->RangeMultiplier(2) - ->Range(1 << 10, 1 << 16) + ->Range(1 << 10, 1U << 24) + ->UseManualTime() ->Complexity(benchmark::oNLogN); BENCHMARK(BM_Complexity_O_N_log_N) ->RangeMultiplier(2) - ->Range(1 << 10, 1 << 16) + ->Range(1 << 10, 1U << 24) + ->UseManualTime() + ->Complexity(); +BENCHMARK(BM_Complexity_O_N_log_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1U << 24) + ->UseManualTime() ->Complexity([](benchmark::IterationCount n) { return kLog2E * static_cast(n) * std::log(static_cast(n)); }); -BENCHMARK(BM_Complexity_O_N_log_N) - ->RangeMultiplier(2) - ->Range(1 << 10, 1 << 16) - ->Complexity(); -const char *n_lg_n_test_name = "BM_Complexity_O_N_log_N"; -const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_BigO"; -const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_RMS"; +const char *n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time"; +const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time_BigO"; +const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time_RMS"; const char *enum_auto_big_o_n_lg_n = "NlgN"; const char *lambda_big_o_n_lg_n = "f\\(N\\)"; @@ -193,11 +220,16 @@ ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n, /*family_index=*/6); -// Add lambda tests +// NOTE: auto big-o is wron.g ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, - rms_o_n_lg_n_test_name, lambda_big_o_n_lg_n, + rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n, /*family_index=*/7); +//// Add lambda tests +ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, + rms_o_n_lg_n_test_name, lambda_big_o_n_lg_n, + /*family_index=*/8); + // ========================================================================= // // -------- Testing formatting of Complexity with captured args ------------ // // ========================================================================= // @@ -205,21 +237,31 @@ ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); - benchmark::DoNotOptimize(iterations); + benchmark::DoNotOptimize(state.iterations()); + double tmp = state.iterations(); + benchmark::DoNotOptimize(tmp); + for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { + benchmark::DoNotOptimize(state.iterations()); + tmp *= state.iterations(); + benchmark::DoNotOptimize(tmp); + } + + state.SetIterationTime(state.range(0) * 42 * 1e-9); } state.SetComplexityN(n); } BENCHMARK_CAPTURE(BM_ComplexityCaptureArgs, capture_test, 100) + ->UseManualTime() ->Complexity(benchmark::oN) ->Ranges({{1, 2}, {3, 4}}); const std::string complexity_capture_name = - "BM_ComplexityCaptureArgs/capture_test"; + "BM_ComplexityCaptureArgs/capture_test/manual_time"; ADD_COMPLEXITY_CASES(complexity_capture_name, complexity_capture_name + "_BigO", - complexity_capture_name + "_RMS", "N", /*family_index=*/9); + complexity_capture_name + "_RMS", "N", + /*family_index=*/9); // ========================================================================= // // --------------------------- TEST CASES END ------------------------------ // diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index 0cd3edbd42..7c68a98929 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -49,7 +49,7 @@ void BM_diagnostic_test(benchmark::State& state) { if (called_once == false) try_invalid_pause_resume(state); for (auto _ : state) { - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } @@ -65,7 +65,7 @@ void BM_diagnostic_test_keep_running(benchmark::State& state) { if (called_once == false) try_invalid_pause_resume(state); while (state.KeepRunning()) { - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } diff --git a/test/link_main_test.cc b/test/link_main_test.cc index e806500a9a..131937eebc 100644 --- a/test/link_main_test.cc +++ b/test/link_main_test.cc @@ -2,7 +2,7 @@ void BM_empty(benchmark::State& state) { for (auto _ : state) { - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } } diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index d94bd5161b..4df674d586 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -14,7 +14,7 @@ class TestMemoryManager : public benchmark::MemoryManager { void BM_empty(benchmark::State& state) { for (auto _ : state) { - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } } diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index b0a3ab0619..3cc593e629 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -14,7 +14,7 @@ BM_DECLARE_string(benchmark_perf_counters); static void BM_Simple(benchmark::State& state) { for (auto _ : state) { - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } } diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index ea5381d20b..7867165d1f 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -96,7 +96,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_basic\",%csv_report$"}}); void BM_bytes_per_second(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } state.SetBytesProcessed(1); @@ -128,7 +128,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_bytes_per_second\",%csv_bytes_report$"}}); void BM_items_per_second(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } state.SetItemsProcessed(1); @@ -409,7 +409,7 @@ ADD_CASES(TC_ConsoleOut, {{"^BM_BigArgs/1073741824 %console_report$"}, void BM_Complexity_O1(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } state.SetComplexityN(state.range(0)); diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index b4c5e154c4..2139a19e25 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -143,7 +143,7 @@ ADD_CASES("BM_error_during_running_ranged_for", void BM_error_after_running(benchmark::State& state) { for (auto _ : state) { - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } if (state.thread_index() <= (state.threads() / 2)) diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index ffd3c0992c..cfc1ab069c 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -64,7 +64,7 @@ ADD_CASES(TC_CSVOut, {{"%csv_header," void BM_Counters_Tabular(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index 4cd8ee3739..22252acbf6 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -67,7 +67,7 @@ int num_calls1 = 0; void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } state.counters["foo"] = 1; @@ -119,7 +119,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec", void BM_Counters_Rate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -163,7 +163,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate); void BM_Invert(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -204,7 +204,7 @@ CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert); void BM_Counters_InvertedRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -333,7 +333,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int", void BM_Counters_AvgThreadsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -421,7 +421,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant", void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -513,7 +513,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations", &CheckAvgIterations); void BM_Counters_kAvgIterationsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = state.iterations(); + auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; From 1576991177ba97a4b2ff6c45950f1fa6e9aa678c Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 20 Feb 2024 16:51:06 +0000 Subject: [PATCH 205/561] fix some warnings --- test/complexity_test.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 0c159cd27d..fb4ad1ad53 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -71,7 +71,7 @@ void BM_Complexity_O1(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + long tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -120,7 +120,7 @@ void BM_Complexity_O_N(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + long tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -129,7 +129,7 @@ void BM_Complexity_O_N(benchmark::State &state) { } // 1ns per iteration per entry - state.SetIterationTime(state.range(0) * 42 * 1e-9); + state.SetIterationTime(static_cast(state.range(0)) * 42.0 * 1e-9); } state.SetComplexityN(state.range(0)); } @@ -178,7 +178,7 @@ static void BM_Complexity_O_N_log_N(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + long tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -186,8 +186,8 @@ static void BM_Complexity_O_N_log_N(benchmark::State &state) { benchmark::DoNotOptimize(tmp); } - state.SetIterationTime(state.range(0) * kLog2E * std::log(state.range(0)) * - 42 * 1e-9); + state.SetIterationTime(static_cast(state.range(0)) * kLog2E * + std::log(state.range(0)) * 42.0 * 1e-9); } state.SetComplexityN(state.range(0)); } @@ -238,7 +238,7 @@ void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + long tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -246,7 +246,7 @@ void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { benchmark::DoNotOptimize(tmp); } - state.SetIterationTime(state.range(0) * 42 * 1e-9); + state.SetIterationTime(static_cast(state.range(0)) * 42.0 * 1e-9); } state.SetComplexityN(n); } From ef88520d6fc3a9a9461938cd2617305403e12362 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 6 Mar 2024 15:40:31 +0300 Subject: [PATCH 206/561] Revert "fix some warnings" (#1762) This reverts commit 1576991177ba97a4b2ff6c45950f1fa6e9aa678c. --- test/complexity_test.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/complexity_test.cc b/test/complexity_test.cc index fb4ad1ad53..0c159cd27d 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -71,7 +71,7 @@ void BM_Complexity_O1(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - long tmp = state.iterations(); + double tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -120,7 +120,7 @@ void BM_Complexity_O_N(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - long tmp = state.iterations(); + double tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -129,7 +129,7 @@ void BM_Complexity_O_N(benchmark::State &state) { } // 1ns per iteration per entry - state.SetIterationTime(static_cast(state.range(0)) * 42.0 * 1e-9); + state.SetIterationTime(state.range(0) * 42 * 1e-9); } state.SetComplexityN(state.range(0)); } @@ -178,7 +178,7 @@ static void BM_Complexity_O_N_log_N(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - long tmp = state.iterations(); + double tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -186,8 +186,8 @@ static void BM_Complexity_O_N_log_N(benchmark::State &state) { benchmark::DoNotOptimize(tmp); } - state.SetIterationTime(static_cast(state.range(0)) * kLog2E * - std::log(state.range(0)) * 42.0 * 1e-9); + state.SetIterationTime(state.range(0) * kLog2E * std::log(state.range(0)) * + 42 * 1e-9); } state.SetComplexityN(state.range(0)); } @@ -238,7 +238,7 @@ void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - long tmp = state.iterations(); + double tmp = state.iterations(); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); @@ -246,7 +246,7 @@ void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { benchmark::DoNotOptimize(tmp); } - state.SetIterationTime(static_cast(state.range(0)) * 42.0 * 1e-9); + state.SetIterationTime(state.range(0) * 42 * 1e-9); } state.SetComplexityN(n); } From 654d8d6cf368233018c3df2f84f1118603839ac5 Mon Sep 17 00:00:00 2001 From: Tiago Freire <67021355+tmiguelf@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:50:45 +0100 Subject: [PATCH 207/561] Fixed LTO issue on no discard variable (#1761) Improve `UseCharPointer()` (thus, `DoNotOptimize()`) under MSVC LTO, make it actually escape the pointer and prevent it from being optimized away. --- src/benchmark.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 31f2cde8ff..563c443800 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -152,8 +152,16 @@ BENCHMARK_EXPORT std::map*& GetGlobalContext() { return global_context; } -// FIXME: wouldn't LTO mess this up? -void UseCharPointer(char const volatile*) {} +static void const volatile* volatile global_force_escape_pointer; + +// FIXME: Verify if LTO still messes this up? +void UseCharPointer(char const volatile* const v) { + // We want to escape the pointer `v` so that the compiler can not eliminate + // computations that produced it. To do that, we escape the pointer by storing + // it into a volatile variable, since generally, volatile store, is not + // something the compiler is allowed to elide. + global_force_escape_pointer = reinterpret_cast(v); +} } // namespace internal From c64b144f42f7e17bfebd3d2220f8daac48e6365c Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:19:56 +0000 Subject: [PATCH 208/561] mitigate clang build warnings -Wconversion (#1763) * mitigate clang build warnings -Wconversion * ensure we have warnings set everywhere and fix some --- BUILD.bazel | 19 ++++++++++++++++++- CMakeLists.txt | 1 + src/benchmark.cc | 3 ++- src/benchmark_register.cc | 5 +++-- src/benchmark_register.h | 4 ++-- src/benchmark_runner.cc | 2 +- src/cycleclock.h | 4 ++-- src/statistics.cc | 4 ++-- src/string_util.cc | 2 +- src/sysinfo.cc | 9 ++++----- src/timers.cc | 4 ++-- test/BUILD | 1 + test/benchmark_gtest.cc | 2 +- test/complexity_test.cc | 24 ++++++++++++------------ 14 files changed, 52 insertions(+), 32 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index d72ae86728..15d836998c 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,5 +1,22 @@ licenses(["notice"]) +COPTS = [ + "-pedantic", + "-pedantic-errors", + "-std=c++11", + "-Wall", + "-Wconversion", + "-Wextra", + "-Wshadow", + # "-Wshorten-64-to-32", + "-Wfloat-equal", + "-fstrict-aliasing", + ## assert() are used a lot in tests upstream, which may be optimised out leading to + ## unused-variable warning. + "-Wno-unused-variable", + "-Werror=old-style-cast", +] + config_setting( name = "qnx", constraint_values = ["@platforms//os:qnx"], @@ -47,7 +64,7 @@ cc_library( ], copts = select({ ":windows": [], - "//conditions:default": ["-Werror=old-style-cast"], + "//conditions:default": COPTS, }), defines = [ "BENCHMARK_STATIC_DEFINE", diff --git a/CMakeLists.txt b/CMakeLists.txt index d9bcc6a493..23b519c250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,6 +190,7 @@ else() add_cxx_compiler_flag(-Wshadow) add_cxx_compiler_flag(-Wfloat-equal) add_cxx_compiler_flag(-Wold-style-cast) + add_cxx_compiler_flag(-Wconversion) if(BENCHMARK_ENABLE_WERROR) add_cxx_compiler_flag(-Werror) endif() diff --git a/src/benchmark.cc b/src/benchmark.cc index 563c443800..1f2f6cc277 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -407,7 +407,8 @@ void RunBenchmarks(const std::vector& benchmarks, benchmarks_with_threads += (benchmark.threads() > 1); runners.emplace_back(benchmark, &perfcounters, reports_for_family); int num_repeats_of_this_instance = runners.back().GetNumRepeats(); - num_repetitions_total += num_repeats_of_this_instance; + num_repetitions_total += + static_cast(num_repeats_of_this_instance); if (reports_for_family) reports_for_family->num_runs_total += num_repeats_of_this_instance; } diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index e447c9a2d3..8ade048225 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -482,8 +482,9 @@ int Benchmark::ArgsCnt() const { const char* Benchmark::GetArgName(int arg) const { BM_CHECK_GE(arg, 0); - BM_CHECK_LT(arg, static_cast(arg_names_.size())); - return arg_names_[arg].c_str(); + size_t uarg = static_cast(arg); + BM_CHECK_LT(uarg, arg_names_.size()); + return arg_names_[uarg].c_str(); } TimeUnit Benchmark::GetTimeUnit() const { diff --git a/src/benchmark_register.h b/src/benchmark_register.h index 53367c707c..be50265f72 100644 --- a/src/benchmark_register.h +++ b/src/benchmark_register.h @@ -24,7 +24,7 @@ typename std::vector::iterator AddPowers(std::vector* dst, T lo, T hi, static const T kmax = std::numeric_limits::max(); // Space out the values in multiples of "mult" - for (T i = static_cast(1); i <= hi; i *= static_cast(mult)) { + for (T i = static_cast(1); i <= hi; i = static_cast(i * mult)) { if (i >= lo) { dst->push_back(i); } @@ -52,7 +52,7 @@ void AddNegatedPowers(std::vector* dst, T lo, T hi, int mult) { const auto it = AddPowers(dst, hi_complement, lo_complement, mult); - std::for_each(it, dst->end(), [](T& t) { t *= -1; }); + std::for_each(it, dst->end(), [](T& t) { t = static_cast(t * -1); }); std::reverse(it, dst->end()); } diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index dcddb437e3..a74bdadd3e 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -235,7 +235,7 @@ BenchmarkRunner::BenchmarkRunner( has_explicit_iteration_count(b.iterations() != 0 || parsed_benchtime_flag.tag == BenchTimeType::ITERS), - pool(b.threads() - 1), + pool(static_cast(b.threads() - 1)), iters(has_explicit_iteration_count ? ComputeIters(b_, parsed_benchtime_flag) : 1), diff --git a/src/cycleclock.h b/src/cycleclock.h index eff563e7fa..91abcf9dba 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -70,7 +70,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { // frequency scaling). Also note that when the Mac sleeps, this // counter pauses; it does not continue counting, nor does it // reset to zero. - return mach_absolute_time(); + return static_cast(mach_absolute_time()); #elif defined(BENCHMARK_OS_EMSCRIPTEN) // this goes above x86-specific code because old versions of Emscripten // define __x86_64__, although they have nothing to do with it. @@ -82,7 +82,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { #elif defined(__x86_64__) || defined(__amd64__) uint64_t low, high; __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); - return (high << 32) | low; + return static_cast((high << 32) | low); #elif defined(__powerpc__) || defined(__ppc__) // This returns a time-base, which is not always precisely a cycle-count. #if defined(__powerpc64__) || defined(__ppc64__) diff --git a/src/statistics.cc b/src/statistics.cc index 261dcb299a..16b60261fd 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -97,7 +97,7 @@ std::vector ComputeStats( auto error_count = std::count_if(reports.begin(), reports.end(), [](Run const& run) { return run.skipped; }); - if (reports.size() - error_count < 2) { + if (reports.size() - static_cast(error_count) < 2) { // We don't report aggregated data if there was a single run. return results; } @@ -179,7 +179,7 @@ std::vector ComputeStats( // Similarly, if there are N repetitions with 1 iterations each, // an aggregate will be computed over N measurements, not 1. // Thus it is best to simply use the count of separate reports. - data.iterations = reports.size(); + data.iterations = static_cast(reports.size()); data.real_accumulated_time = Stat.compute_(real_accumulated_time_stat); data.cpu_accumulated_time = Stat.compute_(cpu_accumulated_time_stat); diff --git a/src/string_util.cc b/src/string_util.cc index c69e40a813..9ba63a700a 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -56,7 +56,7 @@ void ToExponentAndMantissa(double val, int precision, double one_k, scaled /= one_k; if (scaled <= big_threshold) { mantissa_stream << scaled; - *exponent = i + 1; + *exponent = static_cast(i + 1); *mantissa = mantissa_stream.str(); return; } diff --git a/src/sysinfo.cc b/src/sysinfo.cc index daeb98b026..57a23e7bc0 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -350,7 +350,7 @@ std::vector GetCacheSizesWindows() { CPUInfo::CacheInfo C; C.num_sharing = static_cast(b.count()); C.level = cache.Level; - C.size = cache.Size; + C.size = static_cast(cache.Size); C.type = "Unknown"; switch (cache.Type) { case CacheUnified: @@ -485,9 +485,8 @@ int GetNumCPUsImpl() { // positives. std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO)); GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; // number of logical - // processors in the current - // group + // number of logical processors in the current group + return static_cast(sysinfo.dwNumberOfProcessors); #elif defined(BENCHMARK_OS_SOLARIS) // Returns -1 in case of a failure. long num_cpu = sysconf(_SC_NPROCESSORS_ONLN); @@ -837,7 +836,7 @@ std::vector GetLoadAvg() { !(defined(__ANDROID__) && __ANDROID_API__ < 29) static constexpr int kMaxSamples = 3; std::vector res(kMaxSamples, 0.0); - const int nelem = getloadavg(res.data(), kMaxSamples); + const size_t nelem = static_cast(getloadavg(res.data(), kMaxSamples)); if (nelem < 1) { res.clear(); } else { diff --git a/src/timers.cc b/src/timers.cc index 667e7b2eef..d0821f3166 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -245,9 +245,9 @@ std::string LocalDateTimeString() { tz_offset_sign = '-'; } - tz_len = + tz_len = static_cast( ::snprintf(tz_offset, sizeof(tz_offset), "%c%02li:%02li", - tz_offset_sign, offset_minutes / 100, offset_minutes % 100); + tz_offset_sign, offset_minutes / 100, offset_minutes % 100)); BM_CHECK(tz_len == kTzOffsetLen); ((void)tz_len); // Prevent unused variable warning in optimized build. } else { diff --git a/test/BUILD b/test/BUILD index e43b802350..b245fa7622 100644 --- a/test/BUILD +++ b/test/BUILD @@ -21,6 +21,7 @@ TEST_COPTS = [ ## assert() are used a lot in tests upstream, which may be optimised out leading to ## unused-variable warning. "-Wno-unused-variable", + "-Werror=old-style-cast", ] # Some of the issues with DoNotOptimize only occur when optimization is enabled diff --git a/test/benchmark_gtest.cc b/test/benchmark_gtest.cc index 2c9e555d92..0aa2552c1e 100644 --- a/test/benchmark_gtest.cc +++ b/test/benchmark_gtest.cc @@ -38,7 +38,7 @@ TEST(AddRangeTest, Advanced64) { TEST(AddRangeTest, FullRange8) { std::vector dst; - AddRange(&dst, int8_t{1}, std::numeric_limits::max(), int8_t{8}); + AddRange(&dst, int8_t{1}, std::numeric_limits::max(), 8); EXPECT_THAT( dst, testing::ElementsAre(int8_t{1}, int8_t{8}, int8_t{64}, int8_t{127})); } diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 0c159cd27d..0729d15aa7 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -71,11 +71,11 @@ void BM_Complexity_O1(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + double tmp = static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); - tmp *= state.iterations(); + tmp *= static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); } @@ -120,16 +120,16 @@ void BM_Complexity_O_N(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + double tmp = static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); - tmp *= state.iterations(); + tmp *= static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); } // 1ns per iteration per entry - state.SetIterationTime(state.range(0) * 42 * 1e-9); + state.SetIterationTime(static_cast(state.range(0)) * 42 * 1e-9); } state.SetComplexityN(state.range(0)); } @@ -178,16 +178,16 @@ static void BM_Complexity_O_N_log_N(benchmark::State &state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + double tmp = static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); - tmp *= state.iterations(); + tmp *= static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); } - state.SetIterationTime(state.range(0) * kLog2E * std::log(state.range(0)) * - 42 * 1e-9); + state.SetIterationTime(static_cast(state.range(0)) * kLog2E * + std::log(state.range(0)) * 42 * 1e-9); } state.SetComplexityN(state.range(0)); } @@ -238,15 +238,15 @@ void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); - double tmp = state.iterations(); + double tmp = static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { benchmark::DoNotOptimize(state.iterations()); - tmp *= state.iterations(); + tmp *= static_cast(state.iterations()); benchmark::DoNotOptimize(tmp); } - state.SetIterationTime(state.range(0) * 42 * 1e-9); + state.SetIterationTime(static_cast(state.range(0)) * 42 * 1e-9); } state.SetComplexityN(n); } From eaafe694d27f31fe05dd9d055da1e57c8d37a004 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Thu, 7 Mar 2024 13:28:55 +0100 Subject: [PATCH 209/561] Add Python bindings build using bzlmod (#1764) * Add a bzlmod Python bindings build Uses the newly started `@nanobind_bazel` project to build nanobind extensions. This means that we can drop all in-tree custom build defs and build files for nanobind and the C++ Python headers. Additionally, the temporary WORKSPACE overwrite hack naturally goes away due to the WORKSPACE system being obsolete. * Bump ruff -> v0.3.1, change ruff settings The latest minor releases incurred some formatting and configuration changes, this commit rolls them out. --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- MODULE.bazel | 22 +++- WORKSPACE | 6 - bindings/python/BUILD | 3 - bindings/python/build_defs.bzl | 29 ---- bindings/python/google_benchmark/BUILD | 18 +-- bindings/python/google_benchmark/__init__.py | 1 + bindings/python/nanobind.BUILD | 59 --------- bindings/python/python_headers.BUILD | 10 -- pyproject.toml | 3 +- setup.py | 132 +++++++++---------- tools/gbench/util.py | 6 +- 12 files changed, 92 insertions(+), 199 deletions(-) delete mode 100644 bindings/python/BUILD delete mode 100644 bindings/python/build_defs.bzl delete mode 100644 bindings/python/nanobind.BUILD delete mode 100644 bindings/python/python_headers.BUILD diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0247d1b062..93455ab60d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.13 + rev: v0.3.1 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/MODULE.bazel b/MODULE.bazel index 7e0e016123..45238d6f9d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,11 +4,11 @@ module( ) bazel_dep(name = "bazel_skylib", version = "1.5.0") -bazel_dep(name = "platforms", version = "0.0.7") +bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "rules_foreign_cc", version = "0.10.1") bazel_dep(name = "rules_cc", version = "0.0.9") -bazel_dep(name = "rules_python", version = "0.27.1", dev_dependency = True) +bazel_dep(name = "rules_python", version = "0.31.0", dev_dependency = True) bazel_dep(name = "googletest", version = "1.12.1", dev_dependency = True, repo_name = "com_google_googletest") bazel_dep(name = "libpfm", version = "4.11.0") @@ -19,7 +19,18 @@ bazel_dep(name = "libpfm", version = "4.11.0") # of relying on the changing default version from rules_python. python = use_extension("@rules_python//python/extensions:python.bzl", "python", dev_dependency = True) +python.toolchain(python_version = "3.8") python.toolchain(python_version = "3.9") +python.toolchain(python_version = "3.10") +python.toolchain(python_version = "3.11") +python.toolchain( + is_default = True, + python_version = "3.12", +) +use_repo( + python, + python = "python_versions", +) pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) pip.parse( @@ -30,3 +41,10 @@ pip.parse( use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # + +bazel_dep(name = "nanobind_bazel", version = "", dev_dependency = True) +git_override( + module_name = "nanobind_bazel", + commit = "97e3db2744d3f5da244a0846a0644ffb074b4880", + remote = "https://github.com/nicholasjng/nanobind-bazel", +) diff --git a/WORKSPACE b/WORKSPACE index 2562070225..503202465e 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -22,9 +22,3 @@ pip_parse( load("@tools_pip_deps//:requirements.bzl", "install_deps") install_deps() - -new_local_repository( - name = "python_headers", - build_file = "@//bindings/python:python_headers.BUILD", - path = "", # May be overwritten by setup.py. -) diff --git a/bindings/python/BUILD b/bindings/python/BUILD deleted file mode 100644 index d61dcb12a1..0000000000 --- a/bindings/python/BUILD +++ /dev/null @@ -1,3 +0,0 @@ -exports_files(glob(["*.BUILD"])) - -exports_files(["build_defs.bzl"]) diff --git a/bindings/python/build_defs.bzl b/bindings/python/build_defs.bzl deleted file mode 100644 index b0c1b0f580..0000000000 --- a/bindings/python/build_defs.bzl +++ /dev/null @@ -1,29 +0,0 @@ -""" -This file contains some build definitions for C++ extensions used in the Google Benchmark Python bindings. -""" - -_SHARED_LIB_SUFFIX = { - "//conditions:default": ".so", - "//:windows": ".dll", -} - -def py_extension(name, srcs, hdrs = [], copts = [], features = [], deps = []): - for shared_lib_suffix in _SHARED_LIB_SUFFIX.values(): - shared_lib_name = name + shared_lib_suffix - native.cc_binary( - name = shared_lib_name, - linkshared = True, - linkstatic = True, - srcs = srcs + hdrs, - copts = copts, - features = features, - deps = deps, - ) - - return native.py_library( - name = name, - data = select({ - platform: [name + shared_lib_suffix] - for platform, shared_lib_suffix in _SHARED_LIB_SUFFIX.items() - }), - ) diff --git a/bindings/python/google_benchmark/BUILD b/bindings/python/google_benchmark/BUILD index f516a693eb..0c8e3c103f 100644 --- a/bindings/python/google_benchmark/BUILD +++ b/bindings/python/google_benchmark/BUILD @@ -1,4 +1,4 @@ -load("//bindings/python:build_defs.bzl", "py_extension") +load("@nanobind_bazel//:build_defs.bzl", "nanobind_extension") py_library( name = "google_benchmark", @@ -9,22 +9,10 @@ py_library( ], ) -py_extension( +nanobind_extension( name = "_benchmark", srcs = ["benchmark.cc"], - copts = [ - "-fexceptions", - "-fno-strict-aliasing", - ], - features = [ - "-use_header_modules", - "-parse_headers", - ], - deps = [ - "//:benchmark", - "@nanobind", - "@python_headers", - ], + deps = ["//:benchmark"], ) py_test( diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index e14769f451..c1393b4e58 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -26,6 +26,7 @@ def my_benchmark(state): if __name__ == '__main__': benchmark.main() """ + import atexit from absl import app diff --git a/bindings/python/nanobind.BUILD b/bindings/python/nanobind.BUILD deleted file mode 100644 index 9874b80d1f..0000000000 --- a/bindings/python/nanobind.BUILD +++ /dev/null @@ -1,59 +0,0 @@ -load("@bazel_skylib//lib:selects.bzl", "selects") - -licenses(["notice"]) - -package(default_visibility = ["//visibility:public"]) - -config_setting( - name = "msvc_compiler", - flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"}, -) - -selects.config_setting_group( - name = "winplusmsvc", - match_all = [ - "@platforms//os:windows", - ":msvc_compiler", - ], -) - -cc_library( - name = "nanobind", - srcs = glob([ - "src/*.cpp", - ]), - additional_linker_inputs = select({ - "@platforms//os:macos": [":cmake/darwin-ld-cpython.sym"], - "//conditions:default": [], - }), - copts = select({ - ":msvc_compiler": [ - "/EHsc", # exceptions - "/Os", # size optimizations - "/GL", # LTO / whole program optimization - ], - # these should work on both clang and gcc. - "//conditions:default": [ - "-fexceptions", - "-flto", - "-Os", - ], - }), - includes = [ - "ext/robin_map/include", - "include", - ], - linkopts = select({ - ":winplusmsvc": ["/LTGC"], # Windows + MSVC. - "@platforms//os:macos": ["-Wl,@$(location :cmake/darwin-ld-cpython.sym)"], # Apple. - "//conditions:default": [], - }), - textual_hdrs = glob( - [ - "include/**/*.h", - "src/*.h", - "ext/robin_map/include/tsl/*.h", - ], - ), - deps = ["@python_headers"], -) diff --git a/bindings/python/python_headers.BUILD b/bindings/python/python_headers.BUILD deleted file mode 100644 index 8f139f8621..0000000000 --- a/bindings/python/python_headers.BUILD +++ /dev/null @@ -1,10 +0,0 @@ -licenses(["notice"]) - -package(default_visibility = ["//visibility:public"]) - -cc_library( - name = "python_headers", - hdrs = glob(["**/*.h"]), - includes = ["."], - visibility = ["//visibility:public"], -) diff --git a/pyproject.toml b/pyproject.toml index aa24ae8c3f..62507a8703 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,11 +75,12 @@ src = ["bindings/python"] line-length = 80 target-version = "py311" +[tool.ruff.lint] # Enable pycodestyle (`E`, `W`), Pyflakes (`F`), and isort (`I`) codes by default. select = ["E", "F", "I", "W"] ignore = [ "E501", # line too long ] -[tool.ruff.isort] +[tool.ruff.lint.isort] combine-as-imports = true diff --git a/setup.py b/setup.py index cb20042da5..910383c769 100644 --- a/setup.py +++ b/setup.py @@ -1,46 +1,27 @@ -import contextlib import os import platform import shutil -import sysconfig from pathlib import Path -from typing import Generator +from typing import Any import setuptools from setuptools.command import build_ext -PYTHON_INCLUDE_PATH_PLACEHOLDER = "" - IS_WINDOWS = platform.system() == "Windows" IS_MAC = platform.system() == "Darwin" - -@contextlib.contextmanager -def temp_fill_include_path(fp: str) -> Generator[None, None, None]: - """Temporarily set the Python include path in a file.""" - with open(fp, "r+") as f: - try: - content = f.read() - replaced = content.replace( - PYTHON_INCLUDE_PATH_PLACEHOLDER, - Path(sysconfig.get_paths()["include"]).as_posix(), - ) - f.seek(0) - f.write(replaced) - f.truncate() - yield - finally: - # revert to the original content after exit - f.seek(0) - f.write(content) - f.truncate() +# hardcoded SABI-related options. Requires that each Python interpreter +# (hermetic or not) participating is of the same major-minor version. +version_tuple = tuple(int(i) for i in platform.python_version_tuple()) +py_limited_api = version_tuple >= (3, 12) +options = {"bdist_wheel": {"py_limited_api": "cp312"}} if py_limited_api else {} class BazelExtension(setuptools.Extension): """A C/C++ extension that is defined as a Bazel BUILD target.""" - def __init__(self, name: str, bazel_target: str): - super().__init__(name=name, sources=[]) + def __init__(self, name: str, bazel_target: str, **kwargs: Any): + super().__init__(name=name, sources=[], **kwargs) self.bazel_target = bazel_target stripped_target = bazel_target.split("//")[-1] @@ -67,49 +48,58 @@ def copy_extensions_to_source(self): def bazel_build(self, ext: BazelExtension) -> None: """Runs the bazel build to create the package.""" - with temp_fill_include_path("WORKSPACE"): - temp_path = Path(self.build_temp) - - bazel_argv = [ - "bazel", - "build", - ext.bazel_target, - "--enable_bzlmod=false", - f"--symlink_prefix={temp_path / 'bazel-'}", - f"--compilation_mode={'dbg' if self.debug else 'opt'}", - # C++17 is required by nanobind - f"--cxxopt={'/std:c++17' if IS_WINDOWS else '-std=c++17'}", - ] - - if IS_WINDOWS: - # Link with python*.lib. - for library_dir in self.library_dirs: - bazel_argv.append("--linkopt=/LIBPATH:" + library_dir) - elif IS_MAC: - if platform.machine() == "x86_64": - # C++17 needs macOS 10.14 at minimum - bazel_argv.append("--macos_minimum_os=10.14") - - # cross-compilation for Mac ARM64 on GitHub Mac x86 runners. - # ARCHFLAGS is set by cibuildwheel before macOS wheel builds. - archflags = os.getenv("ARCHFLAGS", "") - if "arm64" in archflags: - bazel_argv.append("--cpu=darwin_arm64") - bazel_argv.append("--macos_cpus=arm64") - - elif platform.machine() == "arm64": - bazel_argv.append("--macos_minimum_os=11.0") - - self.spawn(bazel_argv) - - shared_lib_suffix = ".dll" if IS_WINDOWS else ".so" - ext_name = ext.target_name + shared_lib_suffix - ext_bazel_bin_path = ( - temp_path / "bazel-bin" / ext.relpath / ext_name - ) - - ext_dest_path = Path(self.get_ext_fullpath(ext.name)) - shutil.copyfile(ext_bazel_bin_path, ext_dest_path) + temp_path = Path(self.build_temp) + # omit the patch version to avoid build errors if the toolchain is not + # yet registered in the current @rules_python version. + # patch version differences should be fine. + python_version = ".".join(platform.python_version_tuple()[:2]) + + bazel_argv = [ + "bazel", + "build", + ext.bazel_target, + f"--symlink_prefix={temp_path / 'bazel-'}", + f"--compilation_mode={'dbg' if self.debug else 'opt'}", + # C++17 is required by nanobind + f"--cxxopt={'/std:c++17' if IS_WINDOWS else '-std=c++17'}", + f"--@rules_python//python/config_settings:python_version={python_version}", + ] + + if ext.py_limited_api: + bazel_argv += ["--@nanobind_bazel//:py-limited-api=cp312"] + + if IS_WINDOWS: + # Link with python*.lib. + for library_dir in self.library_dirs: + bazel_argv.append("--linkopt=/LIBPATH:" + library_dir) + elif IS_MAC: + if platform.machine() == "x86_64": + # C++17 needs macOS 10.14 at minimum + bazel_argv.append("--macos_minimum_os=10.14") + + # cross-compilation for Mac ARM64 on GitHub Mac x86 runners. + # ARCHFLAGS is set by cibuildwheel before macOS wheel builds. + archflags = os.getenv("ARCHFLAGS", "") + if "arm64" in archflags: + bazel_argv.append("--cpu=darwin_arm64") + bazel_argv.append("--macos_cpus=arm64") + + elif platform.machine() == "arm64": + bazel_argv.append("--macos_minimum_os=11.0") + + self.spawn(bazel_argv) + + if IS_WINDOWS: + suffix = ".pyd" + else: + suffix = ".abi3.so" if ext.py_limited_api else ".so" + + ext_name = ext.target_name + suffix + ext_bazel_bin_path = temp_path / "bazel-bin" / ext.relpath / ext_name + ext_dest_path = Path(self.get_ext_fullpath(ext.name)).with_name( + ext_name + ) + shutil.copyfile(ext_bazel_bin_path, ext_dest_path) setuptools.setup( @@ -118,6 +108,8 @@ def bazel_build(self, ext: BazelExtension) -> None: BazelExtension( name="google_benchmark._benchmark", bazel_target="//bindings/python/google_benchmark:_benchmark", + py_limited_api=py_limited_api, ) ], + options=options, ) diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 4d061a3a1e..1119a1a2ca 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -1,5 +1,5 @@ -"""util.py - General utilities for running, loading, and processing benchmarks -""" +"""util.py - General utilities for running, loading, and processing benchmarks""" + import json import os import re @@ -37,7 +37,7 @@ def is_executable_file(filename): elif sys.platform.startswith("win"): return magic_bytes == b"MZ" else: - return magic_bytes == b"\x7FELF" + return magic_bytes == b"\x7fELF" def is_json_file(filename): From ad7c3ff18b9cec0b60706089834f3831fd65a58f Mon Sep 17 00:00:00 2001 From: Afanasyev Ivan Date: Sat, 9 Mar 2024 19:35:18 +0700 Subject: [PATCH 210/561] Fix implicit conversion changes signess warning in perf_counters.cc (#1765) `read_bytes` is `ssize_t` (and we know it's non-negative), we need to explicitly cast it to `size_t`. --- src/perf_counters.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index d466e27e86..2eb97eb46a 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -39,7 +39,8 @@ size_t PerfCounterValues::Read(const std::vector& leaders) { auto read_bytes = ::read(lead, ptr, size); if (read_bytes >= ssize_t(sizeof(uint64_t))) { // Actual data bytes are all bytes minus initial padding - std::size_t data_bytes = read_bytes - sizeof(uint64_t); + std::size_t data_bytes = + static_cast(read_bytes) - sizeof(uint64_t); // This should be very cheap since it's in hot cache std::memmove(ptr, ptr + sizeof(uint64_t), data_bytes); // Increment our counters From 06b4a070156a9333549468e67923a3a16c8f541b Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 18 Mar 2024 14:01:25 +0300 Subject: [PATCH 211/561] clang-tidy broke the world (#1766) `AnalyzeTemporaryDtors` option is no longer recognized by clang-tidy-18, and that renders the whole config invalid and completely ignored... ??? --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 56938a598d..1e229e582e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -2,6 +2,5 @@ Checks: 'clang-analyzer-*,readability-redundant-*,performance-*' WarningsAsErrors: 'clang-analyzer-*,readability-redundant-*,performance-*' HeaderFilterRegex: '.*' -AnalyzeTemporaryDtors: false FormatStyle: none User: user From d5c55e8c42a8782cb24f6011d0e88449237ab842 Mon Sep 17 00:00:00 2001 From: PhilipDeegan Date: Thu, 21 Mar 2024 12:29:38 +0000 Subject: [PATCH 212/561] allow BENCHMARK_VERSION to be undefined (#1769) --- src/benchmark.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 1f2f6cc277..337bb3faa7 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -757,7 +757,13 @@ int InitializeStreams() { } // end namespace internal -std::string GetBenchmarkVersion() { return {BENCHMARK_VERSION}; } +std::string GetBenchmarkVersion() { +#ifdef BENCHMARK_VERSION + return {BENCHMARK_VERSION}; +#else + return {""}; +#endif +} void PrintDefaultHelp() { fprintf(stdout, From f3ec7b8820ca8136c4e1dad4552608b51b47831a Mon Sep 17 00:00:00 2001 From: Vasyl Zubko Date: Sun, 24 Mar 2024 20:17:34 +0100 Subject: [PATCH 213/561] Fix OpenBSD build (#1772) --- src/sysinfo.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 57a23e7bc0..73b46a5a1a 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -162,7 +162,7 @@ ValueUnion GetSysctlImp(std::string const& name) { mib[1] = HW_CPUSPEED; } - if (sysctl(mib, 2, buff.data(), &buff.Size, nullptr, 0) == -1) { + if (sysctl(mib, 2, buff.data(), &buff.size, nullptr, 0) == -1) { return ValueUnion(); } return buff; @@ -734,7 +734,7 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { #endif unsigned long long hz = 0; #if defined BENCHMARK_OS_OPENBSD - if (GetSysctl(freqStr, &hz)) return hz * 1000000; + if (GetSysctl(freqStr, &hz)) return static_cast(hz * 1000000); #else if (GetSysctl(freqStr, &hz)) return hz; #endif From 70916cbf71f50b9e1e6f13559e10d6dbb92beb32 Mon Sep 17 00:00:00 2001 From: Fanbo Meng Date: Wed, 3 Apr 2024 05:26:33 -0400 Subject: [PATCH 214/561] Remove COMPILER_IBMXL macro for z/OS (#1777) COMPILER_IBMXL identifies the Clang based IBM XL compiler (xlclang) on z/OS. This compiler is obsolete and replaced by the Open XL compiler, so the macro is no longer needed and the existing code would lead to incorrect asm syntax for Open XL. --- src/cycleclock.h | 5 +++-- src/internal_macros.h | 6 +----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index 91abcf9dba..a25843760b 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -181,10 +181,11 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { #elif defined(__s390__) // Covers both s390 and s390x. // Return the CPU clock. uint64_t tsc; -#if defined(BENCHMARK_OS_ZOS) && defined(COMPILER_IBMXL) - // z/OS XL compiler HLASM syntax. +#if defined(BENCHMARK_OS_ZOS) + // z/OS HLASM syntax. asm(" stck %0" : "=m"(tsc) : : "cc"); #else + // Linux on Z syntax. asm("stck %0" : "=Q"(tsc) : : "cc"); #endif return tsc; diff --git a/src/internal_macros.h b/src/internal_macros.h index 8dd7d0c650..f4894ba8e6 100644 --- a/src/internal_macros.h +++ b/src/internal_macros.h @@ -11,11 +11,7 @@ #endif #if defined(__clang__) - #if defined(__ibmxl__) - #if !defined(COMPILER_IBMXL) - #define COMPILER_IBMXL - #endif - #elif !defined(COMPILER_CLANG) + #if !defined(COMPILER_CLANG) #define COMPILER_CLANG #endif #elif defined(_MSC_VER) From d6ce1452872abcd7e5a772f757708a2ad0eee71c Mon Sep 17 00:00:00 2001 From: dhairya <97079960+dhairyarungta@users.noreply.github.com> Date: Sat, 13 Apr 2024 05:22:31 +0800 Subject: [PATCH 215/561] Refactor: Return frequency as double (#1782) Adjusted the GetSysctl call in sysinfo.cc to ensure the frequency value is returned as a double rather than an integer. This helps maintain consistency and clarity in the codebase. --- src/sysinfo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 73b46a5a1a..7261e2a96b 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -736,7 +736,7 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { #if defined BENCHMARK_OS_OPENBSD if (GetSysctl(freqStr, &hz)) return static_cast(hz * 1000000); #else - if (GetSysctl(freqStr, &hz)) return hz; + if (GetSysctl(freqStr, &hz)) return static_cast(hz); #endif fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", freqStr, strerror(errno)); From c0105603f618fdc03bc4ae5ad2be076f039c12f8 Mon Sep 17 00:00:00 2001 From: David Seifert <16636962+SoapGentoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 09:05:36 -0700 Subject: [PATCH 216/561] Add `benchmark_main.pc` to link `main()` containing library (#1779) This is similar to the addition in https://github.com/google/googletest/commit/8604c4adac40573f806cfadae44e22f8dfaf212a#diff-eb8e49bdf5e9aafb996777a4f4302ad1efd281222bf3202eb9b77ce47496c345 that added pkg-config support in GTest. Without this, users need to manually find the library containing `main()`. --- cmake/benchmark_main.pc.in | 7 +++++++ src/CMakeLists.txt | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 cmake/benchmark_main.pc.in diff --git a/cmake/benchmark_main.pc.in b/cmake/benchmark_main.pc.in new file mode 100644 index 0000000000..a90f3cd060 --- /dev/null +++ b/cmake/benchmark_main.pc.in @@ -0,0 +1,7 @@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ + +Name: @PROJECT_NAME@ +Description: Google microbenchmark framework (with main() function) +Version: @VERSION@ +Requires: benchmark +Libs: -L${libdir} -lbenchmark_main diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 943594b70b..5551099b2a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,6 +86,7 @@ set(generated_dir "${PROJECT_BINARY_DIR}") set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake") set(pkg_config "${generated_dir}/${PROJECT_NAME}.pc") +set(pkg_config_main "${generated_dir}/${PROJECT_NAME}_main.pc") set(targets_to_export benchmark benchmark_main) set(targets_export_name "${PROJECT_NAME}Targets") @@ -105,6 +106,7 @@ write_basic_package_version_file( ) configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY) +configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark_main.pc.in" "${pkg_config_main}" @ONLY) export ( TARGETS ${targets_to_export} @@ -133,7 +135,7 @@ if (BENCHMARK_ENABLE_INSTALL) DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") install( - FILES "${pkg_config}" + FILES "${pkg_config}" "${pkg_config_main}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") install( From 185c55d79301f1b3a6505b8432440f7a3994e79a Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 15 Apr 2024 11:57:02 +0200 Subject: [PATCH 217/561] Switch git override to stable BCR tag for nanobind_bazel (#1778) This comes following the first BCR release of nanobind_bazel. Feature-wise, nothing substantial has changed, except that the extensions are stripped of debug info when built in release mode, which reduces clutter in the symbol tables. No stubgen yet, since nanobind v2 has not been released yet. --- MODULE.bazel | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 45238d6f9d..ca7bff6531 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -42,9 +42,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "", dev_dependency = True) -git_override( - module_name = "nanobind_bazel", - commit = "97e3db2744d3f5da244a0846a0644ffb074b4880", - remote = "https://github.com/nicholasjng/nanobind-bazel", -) +bazel_dep(name = "nanobind_bazel", version = "1.0.0", dev_dependency = True) From bc946b919cac6f25a199a526da571638cfde109f Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 15 Apr 2024 18:44:09 +0200 Subject: [PATCH 218/561] Modernize wheel building job config (#1783) It is now possible to build Mac wheels on native machines in Github Actions, so ARM64 Mac wheels are now built and tested on M1 machines. Also, the artifact up-/download was migrated to v4, which made it necessary to upload wheels to unique artifact names, and then later stitch them together again in a subsequent job. The cross-platform Mac build injection in setup.py was removed, since it is no longer necessary. I relanded a monkey-patching of Bazel build files, this time for MODULE.bazel. This is because `rules_python` does not allow running as the root user, which is the case in cibuildwheel+Linux (happens in a Docker container). Since I did not see a quick way of switching to rootless containers, and did not want to hardcode the config change (it can apparently cause cache misses and build failures), I inject the "ignore_root_user_error" flag into the MODULE.bazel file when running in cibuildwheel on Linux. --- .github/install_bazel.sh | 9 +++--- .github/workflows/wheels.yml | 50 +++++++++++++++++----------- MODULE.bazel | 4 --- setup.py | 63 +++++++++++++++++++++++++++--------- 4 files changed, 83 insertions(+), 43 deletions(-) diff --git a/.github/install_bazel.sh b/.github/install_bazel.sh index d07db0e758..1b0d63c98e 100644 --- a/.github/install_bazel.sh +++ b/.github/install_bazel.sh @@ -3,11 +3,10 @@ if ! bazel version; then if [ "$arch" == "aarch64" ]; then arch="arm64" fi - echo "Installing wget and downloading $arch Bazel binary from GitHub releases." - yum install -y wget - wget "https://github.com/bazelbuild/bazel/releases/download/6.4.0/bazel-6.4.0-linux-$arch" -O /usr/local/bin/bazel - chmod +x /usr/local/bin/bazel + echo "Downloading $arch Bazel binary from GitHub releases." + curl -L -o $HOME/bin/bazel --create-dirs "https://github.com/bazelbuild/bazel/releases/download/7.1.1/bazel-7.1.1-linux-$arch" + chmod +x $HOME/bin/bazel else - # bazel is installed for the correct architecture + # Bazel is installed for the correct architecture exit 0 fi diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index a36d312aa6..8b772cd8b9 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,16 +15,16 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Install Python 3.11 + - name: Install Python 3.12 uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: 3.12 - run: python -m pip install build - name: Build sdist run: python -m build --sdist - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: - name: dist + name: dist-sdist path: dist/*.tar.gz build_wheels: @@ -32,7 +32,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-13, macos-14, windows-latest] steps: - name: Check out Google Benchmark @@ -47,32 +47,44 @@ jobs: platforms: all - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.16.2 + uses: pypa/cibuildwheel@v2.17 env: - CIBW_BUILD: 'cp38-* cp39-* cp310-* cp311-* cp312-*' + CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-*" CIBW_SKIP: "*-musllinux_*" - CIBW_TEST_SKIP: "*-macosx_arm64" - CIBW_ARCHS_LINUX: x86_64 aarch64 - CIBW_ARCHS_MACOS: x86_64 arm64 - CIBW_ARCHS_WINDOWS: AMD64 + CIBW_TEST_SKIP: "cp38-macosx_*:arm64" + CIBW_ARCHS_LINUX: auto64 aarch64 + CIBW_ARCHS_WINDOWS: auto64 CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh + # Grab the rootless Bazel installation inside the container. + CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py - name: Upload Google Benchmark ${{ matrix.os }} wheels - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: dist + name: dist-${{ matrix.os }} path: wheelhouse/*.whl + merge_wheels: + name: Merge all built wheels into one artifact + runs-on: ubuntu-latest + needs: build_wheels + steps: + - name: Merge wheels + uses: actions/upload-artifact/merge@v4 + with: + name: dist + pattern: dist-* + delete-merged: true + pypi_upload: name: Publish google-benchmark wheels to PyPI - needs: [build_sdist, build_wheels] + needs: [merge_wheels] runs-on: ubuntu-latest permissions: id-token: write steps: - - uses: actions/download-artifact@v3 - with: - name: dist - path: dist - - uses: pypa/gh-action-pypi-publish@v1.8.11 + - uses: actions/download-artifact@v4 + with: + path: dist + - uses: pypa/gh-action-pypi-publish@v1 diff --git a/MODULE.bazel b/MODULE.bazel index ca7bff6531..95db0b1292 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -27,10 +27,6 @@ python.toolchain( is_default = True, python_version = "3.12", ) -use_repo( - python, - python = "python_versions", -) pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) pip.parse( diff --git a/setup.py b/setup.py index 910383c769..40cdc8d339 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,17 @@ +import contextlib import os import platform +import re import shutil from pathlib import Path -from typing import Any +from typing import Any, Generator import setuptools from setuptools.command import build_ext IS_WINDOWS = platform.system() == "Windows" IS_MAC = platform.system() == "Darwin" +IS_LINUX = platform.system() == "Linux" # hardcoded SABI-related options. Requires that each Python interpreter # (hermetic or not) participating is of the same major-minor version. @@ -17,6 +20,46 @@ options = {"bdist_wheel": {"py_limited_api": "cp312"}} if py_limited_api else {} +def is_cibuildwheel() -> bool: + return os.getenv("CIBUILDWHEEL") is not None + + +@contextlib.contextmanager +def _maybe_patch_toolchains() -> Generator[None, None, None]: + """ + Patch rules_python toolchains to ignore root user error + when run in a Docker container on Linux in cibuildwheel. + """ + + def fmt_toolchain_args(matchobj): + suffix = "ignore_root_user_error = True" + callargs = matchobj.group(1) + # toolchain def is broken over multiple lines + if callargs.endswith("\n"): + callargs = callargs + " " + suffix + ",\n" + # toolchain def is on one line. + else: + callargs = callargs + ", " + suffix + return "python.toolchain(" + callargs + ")" + + CIBW_LINUX = is_cibuildwheel() and IS_LINUX + try: + if CIBW_LINUX: + module_bazel = Path("MODULE.bazel") + content: str = module_bazel.read_text() + module_bazel.write_text( + re.sub( + r"python.toolchain\(([\w\"\s,.=]*)\)", + fmt_toolchain_args, + content, + ) + ) + yield + finally: + if CIBW_LINUX: + module_bazel.write_text(content) + + class BazelExtension(setuptools.Extension): """A C/C++ extension that is defined as a Bazel BUILD target.""" @@ -73,21 +116,11 @@ def bazel_build(self, ext: BazelExtension) -> None: for library_dir in self.library_dirs: bazel_argv.append("--linkopt=/LIBPATH:" + library_dir) elif IS_MAC: - if platform.machine() == "x86_64": - # C++17 needs macOS 10.14 at minimum - bazel_argv.append("--macos_minimum_os=10.14") - - # cross-compilation for Mac ARM64 on GitHub Mac x86 runners. - # ARCHFLAGS is set by cibuildwheel before macOS wheel builds. - archflags = os.getenv("ARCHFLAGS", "") - if "arm64" in archflags: - bazel_argv.append("--cpu=darwin_arm64") - bazel_argv.append("--macos_cpus=arm64") - - elif platform.machine() == "arm64": - bazel_argv.append("--macos_minimum_os=11.0") + # C++17 needs macOS 10.14 at minimum + bazel_argv.append("--macos_minimum_os=10.14") - self.spawn(bazel_argv) + with _maybe_patch_toolchains(): + self.spawn(bazel_argv) if IS_WINDOWS: suffix = ".pyd" From a4cf155615c63e019ae549e31703bf367df5b471 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 23 May 2024 15:02:46 +0100 Subject: [PATCH 219/561] preparing for v1.8.4 (#1788) --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23b519c250..71396edacb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.10...3.22) -project (benchmark VERSION 1.8.3 LANGUAGES CXX) +project (benchmark VERSION 1.8.4 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 95db0b1292..0624a34f01 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.8.3", + version = "1.8.4", ) bazel_dep(name = "bazel_skylib", version = "1.5.0") From 7f992a553df82688e68b72228f5fbb533b04b750 Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Thu, 23 May 2024 10:08:54 -0700 Subject: [PATCH 220/561] Improve compatibility with Hexagon hardware (#1785) The customization done via BENCHMARK_OS_QURT works just fine with the Hexagon simulator, but on at least some Hexagon hardware, both `qurt_timer_get_ticks()` and `std::chrono::now()` are broken and always return 0. This fixes the former by using the better-supported (and essentially identical `qurt_sysclock_get_hw_ticks()` call, and the latter by reading a 19.2MHz hardware counter (per suggestion from Qualcomm). Local testing seems to indicate these changes are just as robust under the simulator as before. --- src/timers.cc | 12 ++++++++++-- src/timers.h | 29 ++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/timers.cc b/src/timers.cc index d0821f3166..7ba540b88b 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -126,8 +126,12 @@ double ProcessCPUUsage() { return MakeTime(kernel_time, user_time); DiagnoseAndExit("GetProccessTimes() failed"); #elif defined(BENCHMARK_OS_QURT) + // Note that qurt_timer_get_ticks() is no longer documented as of SDK 5.3.0, + // and doesn't appear to work on at least some devices (eg Samsung S22), + // so let's use the actually-documented and apparently-equivalent + // qurt_sysclock_get_hw_ticks() call instead. return static_cast( - qurt_timer_timetick_to_us(qurt_timer_get_ticks())) * + qurt_timer_timetick_to_us(qurt_sysclock_get_hw_ticks())) * 1.0e-6; #elif defined(BENCHMARK_OS_EMSCRIPTEN) // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten. @@ -160,8 +164,12 @@ double ThreadCPUUsage() { &user_time); return MakeTime(kernel_time, user_time); #elif defined(BENCHMARK_OS_QURT) + // Note that qurt_timer_get_ticks() is no longer documented as of SDK 5.3.0, + // and doesn't appear to work on at least some devices (eg Samsung S22), + // so let's use the actually-documented and apparently-equivalent + // qurt_sysclock_get_hw_ticks() call instead. return static_cast( - qurt_timer_timetick_to_us(qurt_timer_get_ticks())) * + qurt_timer_timetick_to_us(qurt_sysclock_get_hw_ticks())) * 1.0e-6; #elif defined(BENCHMARK_OS_MACOSX) // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. diff --git a/src/timers.h b/src/timers.h index 65606ccd93..690086b36c 100644 --- a/src/timers.h +++ b/src/timers.h @@ -15,6 +15,29 @@ double ChildrenCPUUsage(); // Return the CPU usage of the current thread double ThreadCPUUsage(); +#if defined(BENCHMARK_OS_QURT) + +// std::chrono::now() can return 0 on some Hexagon devices; +// this reads the value of a 56-bit, 19.2MHz hardware counter +// and converts it to seconds. Unlike std::chrono, this doesn't +// return an absolute time, but since ChronoClockNow() is only used +// to compute elapsed time, this shouldn't matter. +struct QuRTClock { + typedef uint64_t rep; + typedef std::ratio<1, 19200000> period; + typedef std::chrono::duration duration; + typedef std::chrono::time_point time_point; + static const bool is_steady = false; + + static time_point now() { + unsigned long long count; + asm volatile(" %0 = c31:30 " : "=r"(count)); + return time_point(static_cast(count)); + } +}; + +#else + #if defined(HAVE_STEADY_CLOCK) template struct ChooseSteadyClock { @@ -25,10 +48,14 @@ template <> struct ChooseSteadyClock { typedef std::chrono::steady_clock type; }; +#endif // HAVE_STEADY_CLOCK + #endif struct ChooseClockType { -#if defined(HAVE_STEADY_CLOCK) +#if defined(BENCHMARK_OS_QURT) + typedef QuRTClock type; +#elif defined(HAVE_STEADY_CLOCK) typedef ChooseSteadyClock<>::type type; #else typedef std::chrono::high_resolution_clock type; From 144d23cf5fa0b1b9dd138bc56601920d83e350c7 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Fri, 24 May 2024 10:51:41 +0200 Subject: [PATCH 221/561] hotfix: Correct pypi-publishing action tag to v1.8.14 (#1791) Also bump pre-commit dependencies via `pre-commit autoupdate`. --- .github/workflows/wheels.yml | 2 +- .pre-commit-config.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 8b772cd8b9..591d709fba 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -87,4 +87,4 @@ jobs: - uses: actions/download-artifact@v4 with: path: dist - - uses: pypa/gh-action-pypi-publish@v1 + - uses: pypa/gh-action-pypi-publish@v1.8.14 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93455ab60d..a019caf416 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,13 +5,13 @@ repos: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 + rev: v1.10.0 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.1 + rev: v0.4.5 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] From d77b69271091c35b1da5d47894d924832f8cfc37 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 28 May 2024 13:24:21 +0300 Subject: [PATCH 222/561] CMake: unbreak version handling for tarballs (#1793) #1742 changed the placeholder version from `0.0.0` to `v0.0.0`, but this line which was further dealing with it, was not updated. Fixes https://github.com/google/benchmark/issues/1792 Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71396edacb..942ce98c58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ get_git_version(GIT_VERSION) # If no git version can be determined, use the version # from the project() command -if ("${GIT_VERSION}" STREQUAL "0.0.0") +if ("${GIT_VERSION}" STREQUAL "v0.0.0") set(VERSION "v${benchmark_VERSION}") else() set(VERSION "${GIT_VERSION}") From 7f0e99af540a333108b92d792923ec7fc9e9fad9 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Tue, 28 May 2024 20:14:54 -0700 Subject: [PATCH 223/561] cycleclock: Fix type conversion to match function return type (#1794) fixes build with clang19 src/cycleclock.h:208:52: error: implicit conversion changes signedness: 'uint64_t' (aka 'unsigned long long') to 'int64_t' (aka 'long long') [-Werror,-Wsign-conversion] 208 | return (static_cast(cycles_hi1) << 32) | cycles_lo; | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~ 1 error generated. --- src/cycleclock.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index a25843760b..c657414e56 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -205,7 +205,8 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { "sub %0, zero, %0\n" "and %1, %1, %0\n" : "=r"(cycles_hi0), "=r"(cycles_lo), "=r"(cycles_hi1)); - return (static_cast(cycles_hi1) << 32) | cycles_lo; + return static_cast((static_cast(cycles_hi1) << 32) | + cycles_lo); #else uint64_t cycles; asm volatile("rdtime %0" : "=r"(cycles)); From 10199fb48ec4fab83c93ef59c3156ef44584450a Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Fri, 7 Jun 2024 15:22:45 +0100 Subject: [PATCH 224/561] bump standard to C++14 (#1799) * update requirements to point to our dependencies doc * bump standard to c++14 --- BUILD.bazel | 2 +- CMakeLists.txt | 6 +----- README.md | 8 +++----- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 15d836998c..f7a1162baa 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3,7 +3,7 @@ licenses(["notice"]) COPTS = [ "-pedantic", "-pedantic-errors", - "-std=c++11", + "-std=c++14", "-Wall", "-Wconversion", "-Wextra", diff --git a/CMakeLists.txt b/CMakeLists.txt index 942ce98c58..77eb30a3ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,11 +138,7 @@ if (BENCHMARK_BUILD_32_BITS) add_required_cxx_compiler_flag(-m32) endif() -if (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - set(BENCHMARK_CXX_STANDARD 14) -else() - set(BENCHMARK_CXX_STANDARD 11) -endif() +set(BENCHMARK_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD ${BENCHMARK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED YES) diff --git a/README.md b/README.md index a5e5d392d8..0b2a0ab63f 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,10 @@ IRC channels: The library can be used with C++03. However, it requires C++11 to build, including compiler and standard library support. -The following minimum versions are required to build the library: +_See [dependencies.md](docs/dependencies.md) for more details regarding supported +compilers and standards._ -* GCC 4.8 -* Clang 3.4 -* Visual Studio 14 2015 -* Intel 2015 Update 1 +If you have need for a particular compiler to be supported, patches are very welcome. See [Platform-Specific Build Instructions](docs/platform_specific_build_instructions.md). From 2fa4b26e5825d0b17577ae038c3b75e2d6b5418b Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Mon, 10 Jun 2024 12:08:49 +0200 Subject: [PATCH 225/561] Bump minimum required C++ version from C++11 to C++14 (#1800) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b2a0ab63f..8e5428f995 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ IRC channels: ## Requirements -The library can be used with C++03. However, it requires C++11 to build, +The library can be used with C++03. However, it requires C++14 to build, including compiler and standard library support. _See [dependencies.md](docs/dependencies.md) for more details regarding supported From 8e1823d6f59c1d0fdc084fd903c989e6816ea097 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Tue, 11 Jun 2024 05:37:35 -0700 Subject: [PATCH 226/561] cycleclock: Fix type conversion to match function return type on riscv64 (#1802) Fixes builds with clang src/cycleclock.h:213:10: error: implicit conversion changes signedness: 'uint64_t' (aka 'unsigned long') to 'int64_t' (aka 'long') [-Werror,-Wsign-conversion] 213 | return cycles; | ~~~~~~ ^~~~~~ 1 error generated. --- src/cycleclock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index c657414e56..bd62f5d7e7 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -210,7 +210,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { #else uint64_t cycles; asm volatile("rdtime %0" : "=r"(cycles)); - return cycles; + return static_cast(cycles); #endif #elif defined(__e2k__) || defined(__elbrus__) struct timeval tv; From 447752540c71f34d5d71046e08192db181e9b02b Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 17 Jun 2024 01:38:32 -0700 Subject: [PATCH 227/561] [bazel] Use `includes` instead of `strip_include_prefix` (#1803) When using `includes`, consumers will apply the headers using `-isystem`, instead of `-I`. This will allow diagnostics of consumers to not apply to `benchmark`. More info: https://bazel.build/reference/be/c-cpp#cc_library.includes https://bazel.build/reference/be/c-cpp#cc_library.strip_include_prefix gtest uses `includes` as well: https://github.com/google/googletest/blob/1d17ea141d2c11b8917d2c7d029f1c4e2b9769b2/BUILD.bazel#L120 --- BUILD.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index f7a1162baa..094ed62437 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -73,6 +73,7 @@ cc_library( ":perfcounters": ["HAVE_LIBPFM"], "//conditions:default": [], }), + includes = ["include"], linkopts = select({ ":windows": ["-DEFAULTLIB:shlwapi.lib"], "//conditions:default": ["-pthread"], @@ -87,7 +88,6 @@ cc_library( "_LARGEFILE64_SOURCE", "_LARGEFILE_SOURCE", ], - strip_include_prefix = "include", visibility = ["//visibility:public"], deps = select({ ":perfcounters": ["@libpfm"], @@ -102,7 +102,7 @@ cc_library( "include/benchmark/benchmark.h", "include/benchmark/export.h", ], - strip_include_prefix = "include", + includes = ["include"], visibility = ["//visibility:public"], deps = [":benchmark"], ) From c2146397ac69e6589a50f6b4fc6a7355669caed5 Mon Sep 17 00:00:00 2001 From: Stephen Nicholas Swatman Date: Wed, 19 Jun 2024 20:03:42 +0200 Subject: [PATCH 228/561] Find libpfm dependency in installed CMake configs (#1806) Currently, Google Benchmark can be built and installed with support for libpfm, but this can cause a problem if that installation is later called upon by another CMake project. Indeed, while the installed CMake configuration script correctly identifies that it needs to link against libpfm, it doesn't try to find libpfm, meaning that the target will be unavailable. This commit fixes this potential configuration-time error by ensuring that an installation of Google Benchmark will correctly try to find the libpfm dependency when it is used elsewhere. --- cmake/Config.cmake.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in index 2e15f0cf82..3659cfa2a6 100644 --- a/cmake/Config.cmake.in +++ b/cmake/Config.cmake.in @@ -4,4 +4,8 @@ include (CMakeFindDependencyMacro) find_dependency (Threads) +if (@BENCHMARK_ENABLE_LIBPFM@) + find_dependency (PFM) +endif() + include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") From 71f4218c1abf471eed27ccfbf98055a90ace39f6 Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Wed, 3 Jul 2024 14:16:43 -0400 Subject: [PATCH 229/561] Add -lkstat to the .pc for Solaris (#1801) * Add -lkstat to the .pc for Solaris This fixes linking for projects that rely on pkg-config to generate the link line on Solaris. Test plan: Built the project locally on Solaris and verified -kstat appears in the .pc file ``` $ cat lib/pkgconfig/benchmark.pc | grep Libs.private Libs.private: -lpthread -lkstat ``` * Use BENCHMARK_PRIVATE_LINK_LIBRARIES --- cmake/benchmark.pc.in | 2 +- src/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/benchmark.pc.in b/cmake/benchmark.pc.in index 9dae881c79..043f2fc759 100644 --- a/cmake/benchmark.pc.in +++ b/cmake/benchmark.pc.in @@ -8,5 +8,5 @@ Description: Google microbenchmark framework Version: @VERSION@ Libs: -L${libdir} -lbenchmark -Libs.private: -lpthread +Libs.private: -lpthread @BENCHMARK_PRIVATE_LINK_LIBRARIES@ Cflags: -I${includedir} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5551099b2a..d17964f9ba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,7 @@ endif() # We need extra libraries on Solaris if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS") target_link_libraries(benchmark PRIVATE kstat) + set(BENCHMARK_PRIVATE_LINK_LIBRARIES -lkstat) endif() if (NOT BUILD_SHARED_LIBS) From 38df9daf489f7e359bbe6709099f0102398261d6 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Fri, 12 Jul 2024 10:28:16 +0100 Subject: [PATCH 230/561] add PERF_FORMAT_TOTAL_TIME_{ENABLED,RUNNING} to support multiplexing (#1814) --- src/perf_counters.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 2eb97eb46a..e2758afb95 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -157,7 +157,8 @@ PerfCounters PerfCounters::Create( attr.exclude_hv = true; // Read all counters in a group in one read. - attr.read_format = PERF_FORMAT_GROUP; + attr.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; int id = -1; while (id < 0) { From d2cd246e19bdf4de9fe357daec52cbe38303d9d6 Mon Sep 17 00:00:00 2001 From: "Jiawen (Kevin) Chen" Date: Tue, 16 Jul 2024 01:51:56 -0700 Subject: [PATCH 231/561] Clarify the difference between `BENCHMARK_TEMPLATE_F` and `BENCHMARK_TEMPLATE_DEFINE_F` + `BENCHMARK_REGISTER_F` (#1815) * Clarify BENCHMARK_REGISTER_F Add comments highlighting the difference between `BENCHMARK_TEMPLATE_F` and `BENCHMARK_TEMPLATE_DEFINE_F`, mirroring those of `BENCHMARK_F ` and `BENCHMARK_DEFINE_F`. * More informative comments. * Update user_guide.md --- docs/user_guide.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index d22a906909..d87ccc4026 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -624,20 +624,22 @@ public: } }; +// Defines and registers `FooTest` using the class `MyFixture`. BENCHMARK_F(MyFixture, FooTest)(benchmark::State& st) { for (auto _ : st) { ... } } +// Only defines `BarTest` using the class `MyFixture`. BENCHMARK_DEFINE_F(MyFixture, BarTest)(benchmark::State& st) { for (auto _ : st) { ... } } -/* BarTest is NOT registered */ +// `BarTest` is NOT registered. BENCHMARK_REGISTER_F(MyFixture, BarTest)->Threads(2); -/* BarTest is now registered */ +// `BarTest` is now registered. ``` ### Templated Fixtures @@ -653,19 +655,22 @@ For example: template class MyFixture : public benchmark::Fixture {}; +// Defines and registers `IntTest` using the class template `MyFixture`. BENCHMARK_TEMPLATE_F(MyFixture, IntTest, int)(benchmark::State& st) { for (auto _ : st) { ... } } +// Only defines `DoubleTest` using the class template `MyFixture`. BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, DoubleTest, double)(benchmark::State& st) { for (auto _ : st) { ... } } - +// `DoubleTest` is NOT registered. BENCHMARK_REGISTER_F(MyFixture, DoubleTest)->Threads(2); +// `DoubleTest` is now registered. ``` @@ -1012,11 +1017,11 @@ in any way. `` may even be removed entirely when the result is already known. For example: ```c++ - /* Example 1: `` is removed entirely. */ + // Example 1: `` is removed entirely. int foo(int x) { return x + 42; } while (...) DoNotOptimize(foo(0)); // Optimized to DoNotOptimize(42); - /* Example 2: Result of '' is only reused */ + // Example 2: Result of '' is only reused. int bar(int) __attribute__((const)); while (...) DoNotOptimize(bar(0)); // Optimized to: // int __result__ = bar(0); From 7c8ed6b082aa3c7a3402f18e50da4480421d08fd Mon Sep 17 00:00:00 2001 From: xdje42 Date: Tue, 16 Jul 2024 01:56:40 -0700 Subject: [PATCH 232/561] [FR] Add API to provide custom profilers #1807 (#1809) This API is akin to the MemoryManager API and lets tools provide their own profiler which is wrapped in the same way MemoryManager is wrapped. Namely, the profiler provides Start/Stop methods that are called at the start/end of running the benchmark in a separate pass. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- CONTRIBUTORS | 1 + docs/user_guide.md | 15 +++++++++ include/benchmark/benchmark.h | 20 ++++++++++++ src/benchmark.cc | 4 +++ src/benchmark_runner.cc | 59 +++++++++++++++++++++++++---------- src/benchmark_runner.h | 5 +++ test/CMakeLists.txt | 3 ++ test/profiler_manager_test.cc | 43 +++++++++++++++++++++++++ 8 files changed, 134 insertions(+), 16 deletions(-) create mode 100644 test/profiler_manager_test.cc diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9ca2caa3ee..54aba7b56d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -42,6 +42,7 @@ Dominic Hamon Dominik Czarnota Dominik Korman Donald Aingworth +Doug Evans Eric Backus Eric Fiselier Eugene Zhuk diff --git a/docs/user_guide.md b/docs/user_guide.md index d87ccc4026..e38262099d 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1139,6 +1139,21 @@ a report on the number of allocations, bytes used, etc. This data will then be reported alongside other performance data, currently only when using JSON output. + + +## Profiling + +It's often useful to also profile benchmarks in particular ways, in addition to +CPU performance. For this reason, benchmark offers the `RegisterProfilerManager` +method that allows a custom `ProfilerManager` to be injected. + +If set, the `ProfilerManager::AfterSetupStart` and +`ProfilerManager::BeforeTeardownStop` methods will be called at the start and +end of a separate benchmark run to allow user code to collect and report +user-provided profile metrics. + +Output collected from this profiling run must be reported separately. + ## Using RegisterBenchmark(name, fn, args...) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 08cfe29da3..7dd72e27bc 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -416,6 +416,26 @@ class MemoryManager { BENCHMARK_EXPORT void RegisterMemoryManager(MemoryManager* memory_manager); +// If a ProfilerManager is registered (via RegisterProfilerManager()), the +// benchmark will be run an additional time under the profiler to collect and +// report profile metrics for the run of the benchmark. +class ProfilerManager { + public: + virtual ~ProfilerManager() {} + + // This is called after `Setup()` code and right before the benchmark is run. + virtual void AfterSetupStart() = 0; + + // This is called before `Teardown()` code and right after the benchmark + // completes. + virtual void BeforeTeardownStop() = 0; +}; + +// Register a ProfilerManager instance that will be used to collect and report +// profile measurements for benchmark runs. +BENCHMARK_EXPORT +void RegisterProfilerManager(ProfilerManager* profiler_manager); + // Add a key-value pair to output as part of the context stanza in the report. BENCHMARK_EXPORT void AddCustomContext(const std::string& key, const std::string& value); diff --git a/src/benchmark.cc b/src/benchmark.cc index 337bb3faa7..374c5141c9 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -656,6 +656,10 @@ void RegisterMemoryManager(MemoryManager* manager) { internal::memory_manager = manager; } +void RegisterProfilerManager(ProfilerManager* manager) { + internal::profiler_manager = manager; +} + void AddCustomContext(const std::string& key, const std::string& value) { if (internal::global_context == nullptr) { internal::global_context = new std::map(); diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index a74bdadd3e..3a8c3076a4 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -62,6 +62,8 @@ namespace internal { MemoryManager* memory_manager = nullptr; +ProfilerManager* profiler_manager = nullptr; + namespace { static constexpr IterationCount kMaxIterations = 1000000000000; @@ -401,6 +403,41 @@ void BenchmarkRunner::RunWarmUp() { } } +MemoryManager::Result* BenchmarkRunner::RunMemoryManager( + IterationCount memory_iterations) { + // TODO(vyng): Consider making BenchmarkReporter::Run::memory_result an + // optional so we don't have to own the Result here. + // Can't do it now due to cxx03. + memory_results.push_back(MemoryManager::Result()); + MemoryManager::Result* memory_result = &memory_results.back(); + memory_manager->Start(); + std::unique_ptr manager; + manager.reset(new internal::ThreadManager(1)); + b.Setup(); + RunInThread(&b, memory_iterations, 0, manager.get(), + perf_counters_measurement_ptr); + manager->WaitForAllThreads(); + manager.reset(); + b.Teardown(); + memory_manager->Stop(*memory_result); + return memory_result; +} + +void BenchmarkRunner::RunProfilerManager() { + // TODO: Provide a way to specify the number of iterations. + IterationCount profile_iterations = 1; + std::unique_ptr manager; + manager.reset(new internal::ThreadManager(1)); + b.Setup(); + profiler_manager->AfterSetupStart(); + RunInThread(&b, profile_iterations, 0, manager.get(), + /*perf_counters_measurement_ptr=*/nullptr); + manager->WaitForAllThreads(); + profiler_manager->BeforeTeardownStop(); + manager.reset(); + b.Teardown(); +} + void BenchmarkRunner::DoOneRepetition() { assert(HasRepeatsRemaining() && "Already done all repetitions?"); @@ -445,28 +482,18 @@ void BenchmarkRunner::DoOneRepetition() { "then we should have accepted the current iteration run."); } - // Oh, one last thing, we need to also produce the 'memory measurements'.. + // Produce memory measurements if requested. MemoryManager::Result* memory_result = nullptr; IterationCount memory_iterations = 0; if (memory_manager != nullptr) { - // TODO(vyng): Consider making BenchmarkReporter::Run::memory_result an - // optional so we don't have to own the Result here. - // Can't do it now due to cxx03. - memory_results.push_back(MemoryManager::Result()); - memory_result = &memory_results.back(); // Only run a few iterations to reduce the impact of one-time // allocations in benchmarks that are not properly managed. memory_iterations = std::min(16, iters); - memory_manager->Start(); - std::unique_ptr manager; - manager.reset(new internal::ThreadManager(1)); - b.Setup(); - RunInThread(&b, memory_iterations, 0, manager.get(), - perf_counters_measurement_ptr); - manager->WaitForAllThreads(); - manager.reset(); - b.Teardown(); - memory_manager->Stop(*memory_result); + memory_result = RunMemoryManager(memory_iterations); + } + + if (profiler_manager != nullptr) { + RunProfilerManager(); } // Ok, now actually report. diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index db2fa04396..cd34d2d5bb 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -35,6 +35,7 @@ BM_DECLARE_string(benchmark_perf_counters); namespace internal { extern MemoryManager* memory_manager; +extern ProfilerManager* profiler_manager; struct RunResults { std::vector non_aggregates; @@ -113,6 +114,10 @@ class BenchmarkRunner { }; IterationResults DoNIterations(); + MemoryManager::Result* RunMemoryManager(IterationCount memory_iterations); + + void RunProfilerManager(); + IterationCount PredictNumItersNeeded(const IterationResults& i) const; bool ShouldReportIterationResults(const IterationResults& i) const; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1de175f98d..815b581889 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -192,6 +192,9 @@ benchmark_add_test(NAME user_counters_thousands_test COMMAND user_counters_thous compile_output_test(memory_manager_test) benchmark_add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s) +compile_output_test(profiler_manager_test) +benchmark_add_test(NAME profiler_manager_test COMMAND profiler_manager_test --benchmark_min_time=0.01s) + # MSVC does not allow to set the language standard to C++98/03. if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) compile_benchmark_test(cxx03_test) diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc new file mode 100644 index 0000000000..1b3e36c37f --- /dev/null +++ b/test/profiler_manager_test.cc @@ -0,0 +1,43 @@ +// FIXME: WIP + +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +class TestProfilerManager : public benchmark::ProfilerManager { + void AfterSetupStart() override {} + void BeforeTeardownStop() override {} +}; + +void BM_empty(benchmark::State& state) { + for (auto _ : state) { + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); + } +} +BENCHMARK(BM_empty); + +ADD_CASES(TC_ConsoleOut, {{"^BM_empty %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"}, + {"\"family_index\": 0,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_empty\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\"$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}}); + +int main(int argc, char* argv[]) { + std::unique_ptr pm(new TestProfilerManager()); + + benchmark::RegisterProfilerManager(pm.get()); + RunOutputTests(argc, argv); + benchmark::RegisterProfilerManager(nullptr); +} From 14ddd77a90152b190e5f428018245dca9d890761 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 16 Jul 2024 17:39:51 +0100 Subject: [PATCH 233/561] remove old travis config --- .travis.yml | 208 ---------------------------------------------------- 1 file changed, 208 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8cfed3d10d..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,208 +0,0 @@ -sudo: required -dist: trusty -language: cpp - -matrix: - include: - - compiler: gcc - addons: - apt: - packages: - - lcov - env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Coverage - - compiler: gcc - addons: - apt: - packages: - - g++-multilib - - libc6:i386 - env: - - COMPILER=g++ - - C_COMPILER=gcc - - BUILD_TYPE=Debug - - BUILD_32_BITS=ON - - EXTRA_FLAGS="-m32" - - compiler: gcc - addons: - apt: - packages: - - g++-multilib - - libc6:i386 - env: - - COMPILER=g++ - - C_COMPILER=gcc - - BUILD_TYPE=Release - - BUILD_32_BITS=ON - - EXTRA_FLAGS="-m32" - - compiler: gcc - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=g++-6 C_COMPILER=gcc-6 BUILD_TYPE=Debug - - ENABLE_SANITIZER=1 - - EXTRA_FLAGS="-fno-omit-frame-pointer -g -O2 -fsanitize=undefined,address -fuse-ld=gold" - # Clang w/ libc++ - - compiler: clang - dist: xenial - addons: - apt: - packages: - clang-3.8 - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug - - LIBCXX_BUILD=1 - - EXTRA_CXX_FLAGS="-stdlib=libc++" - - compiler: clang - dist: xenial - addons: - apt: - packages: - clang-3.8 - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release - - LIBCXX_BUILD=1 - - EXTRA_CXX_FLAGS="-stdlib=libc++" - # Clang w/ 32bit libc++ - - compiler: clang - dist: xenial - addons: - apt: - packages: - - clang-3.8 - - g++-multilib - - libc6:i386 - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug - - LIBCXX_BUILD=1 - - BUILD_32_BITS=ON - - EXTRA_FLAGS="-m32" - - EXTRA_CXX_FLAGS="-stdlib=libc++" - # Clang w/ 32bit libc++ - - compiler: clang - dist: xenial - addons: - apt: - packages: - - clang-3.8 - - g++-multilib - - libc6:i386 - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release - - LIBCXX_BUILD=1 - - BUILD_32_BITS=ON - - EXTRA_FLAGS="-m32" - - EXTRA_CXX_FLAGS="-stdlib=libc++" - # Clang w/ libc++, ASAN, UBSAN - - compiler: clang - dist: xenial - addons: - apt: - packages: - clang-3.8 - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug - - LIBCXX_BUILD=1 LIBCXX_SANITIZER="Undefined;Address" - - ENABLE_SANITIZER=1 - - EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=undefined,address -fno-sanitize-recover=all" - - EXTRA_CXX_FLAGS="-stdlib=libc++" - - UBSAN_OPTIONS=print_stacktrace=1 - # Clang w/ libc++ and MSAN - - compiler: clang - dist: xenial - addons: - apt: - packages: - clang-3.8 - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug - - LIBCXX_BUILD=1 LIBCXX_SANITIZER=MemoryWithOrigins - - ENABLE_SANITIZER=1 - - EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=memory -fsanitize-memory-track-origins" - - EXTRA_CXX_FLAGS="-stdlib=libc++" - # Clang w/ libc++ and MSAN - - compiler: clang - dist: xenial - addons: - apt: - packages: - clang-3.8 - env: - - INSTALL_GCC6_FROM_PPA=1 - - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=RelWithDebInfo - - LIBCXX_BUILD=1 LIBCXX_SANITIZER=Thread - - ENABLE_SANITIZER=1 - - EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all" - - EXTRA_CXX_FLAGS="-stdlib=libc++" - - os: osx - osx_image: xcode8.3 - compiler: clang - env: - - COMPILER=clang++ - - BUILD_TYPE=Release - - BUILD_32_BITS=ON - - EXTRA_FLAGS="-m32" - -before_script: - - if [ -n "${LIBCXX_BUILD}" ]; then - source .libcxx-setup.sh; - fi - - if [ -n "${ENABLE_SANITIZER}" ]; then - export EXTRA_OPTIONS="-DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF"; - else - export EXTRA_OPTIONS=""; - fi - - mkdir -p build && cd build - -before_install: - - if [ -z "$BUILD_32_BITS" ]; then - export BUILD_32_BITS=OFF && echo disabling 32 bit build; - fi - - if [ -n "${INSTALL_GCC6_FROM_PPA}" ]; then - sudo add-apt-repository -y "ppa:ubuntu-toolchain-r/test"; - sudo apt-get update --option Acquire::Retries=100 --option Acquire::http::Timeout="60"; - fi - -install: - - if [ -n "${INSTALL_GCC6_FROM_PPA}" ]; then - travis_wait sudo -E apt-get -yq --no-install-suggests --no-install-recommends install g++-6; - fi - - if [ "${TRAVIS_OS_NAME}" == "linux" -a "${BUILD_32_BITS}" == "OFF" ]; then - travis_wait sudo -E apt-get -y --no-install-suggests --no-install-recommends install llvm-3.9-tools; - sudo cp /usr/lib/llvm-3.9/bin/FileCheck /usr/local/bin/; - fi - - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then - PATH=~/.local/bin:${PATH}; - pip install --user --upgrade pip; - travis_wait pip install --user cpp-coveralls; - fi - - if [ "${C_COMPILER}" == "gcc-7" -a "${TRAVIS_OS_NAME}" == "osx" ]; then - rm -f /usr/local/include/c++; - brew update; - travis_wait brew install gcc@7; - fi - - if [ "${TRAVIS_OS_NAME}" == "linux" ]; then - sudo apt-get update -qq; - sudo apt-get install -qq unzip cmake3; - wget https://github.com/bazelbuild/bazel/releases/download/3.2.0/bazel-3.2.0-installer-linux-x86_64.sh --output-document bazel-installer.sh; - travis_wait sudo bash bazel-installer.sh; - fi - - if [ "${TRAVIS_OS_NAME}" == "osx" ]; then - curl -L -o bazel-installer.sh https://github.com/bazelbuild/bazel/releases/download/3.2.0/bazel-3.2.0-installer-darwin-x86_64.sh; - travis_wait sudo bash bazel-installer.sh; - fi - -script: - - cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_C_FLAGS="${EXTRA_FLAGS}" -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} ${EXTRA_CXX_FLAGS}" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBENCHMARK_BUILD_32_BITS=${BUILD_32_BITS} ${EXTRA_OPTIONS} .. - - make - - ctest -C ${BUILD_TYPE} --output-on-failure - - bazel test -c dbg --define google_benchmark.have_regex=posix --announce_rc --verbose_failures --test_output=errors --keep_going //test/... - -after_success: - - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then - coveralls --include src --include include --gcov-options '\-lp' --root .. --build-root .; - fi From 65668db27365d29ca4890cb2102e81acb6585b43 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 16 Jul 2024 17:45:30 +0100 Subject: [PATCH 234/561] revert perf counters change until we can do the full version --- src/perf_counters.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index e2758afb95..8e5219bc88 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -157,8 +157,8 @@ PerfCounters PerfCounters::Create( attr.exclude_hv = true; // Read all counters in a group in one read. - attr.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_TOTAL_TIME_ENABLED | - PERF_FORMAT_TOTAL_TIME_RUNNING; + attr.read_format = PERF_FORMAT_GROUP; //| PERF_FORMAT_TOTAL_TIME_ENABLED | + //PERF_FORMAT_TOTAL_TIME_RUNNING; int id = -1; while (id < 0) { From a73c039b1d7a389fb7f5b29ab5e966df4d128fdf Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 17 Jul 2024 13:18:38 +0100 Subject: [PATCH 235/561] roll back fatal error that breaks some platform (wasm) expectations --- src/sysinfo.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 7261e2a96b..708a3e0088 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -508,7 +508,8 @@ int GetNumCPUsImpl() { int max_id = -1; std::ifstream f("/proc/cpuinfo"); if (!f.is_open()) { - PrintErrorAndDie("Failed to open /proc/cpuinfo"); + std::cerr << "Failed to open /proc/cpuinfo\n"; + return -1; } #if defined(__alpha__) const std::string Key = "cpus detected"; From 99410f400c064e071473ba64675fa6604f6941b1 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 17 Jul 2024 13:25:16 +0100 Subject: [PATCH 236/561] clang-format fixes --- src/CMakeLists.txt | 2 +- src/perf_counters.cc | 4 ++-- src/sysinfo.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d17964f9ba..32126c0d24 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Allow the source files to find headers in src/ +#Allow the source files to find headers in src / include(GNUInstallDirs) include_directories(${PROJECT_SOURCE_DIR}/src) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index 8e5219bc88..fa1cbb0e8f 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -157,8 +157,8 @@ PerfCounters PerfCounters::Create( attr.exclude_hv = true; // Read all counters in a group in one read. - attr.read_format = PERF_FORMAT_GROUP; //| PERF_FORMAT_TOTAL_TIME_ENABLED | - //PERF_FORMAT_TOTAL_TIME_RUNNING; + attr.read_format = PERF_FORMAT_GROUP; //| PERF_FORMAT_TOTAL_TIME_ENABLED | + // PERF_FORMAT_TOTAL_TIME_RUNNING; int id = -1; while (id < 0) { diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 708a3e0088..421a0bde38 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -120,7 +120,7 @@ struct ValueUnion { explicit ValueUnion(std::size_t buff_size) : size(sizeof(DataT) + buff_size), - buff(::new (std::malloc(size)) DataT(), &std::free) {} + buff(::new(std::malloc(size)) DataT(), &std::free) {} ValueUnion(ValueUnion&& other) = default; From 299a8b881df5fcd9e2130919c818bb15762b8d28 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 17 Jul 2024 13:27:41 +0100 Subject: [PATCH 237/561] clang format header fixes --- include/benchmark/benchmark.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 7dd72e27bc..dc87676832 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -674,7 +674,7 @@ class Counter { Counter(double v = 0., Flags f = kDefaults, OneK k = kIs1000) : value(v), flags(f), oneK(k) {} - BENCHMARK_ALWAYS_INLINE operator double const &() const { return value; } + BENCHMARK_ALWAYS_INLINE operator double const&() const { return value; } BENCHMARK_ALWAYS_INLINE operator double&() { return value; } }; From 44507bc91ff9a23ad8ad4120cfc6b0d9bd27e2ca Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 17 Jul 2024 16:39:15 +0100 Subject: [PATCH 238/561] another reversal of something that breaks on wasm --- src/sysinfo.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 421a0bde38..4638641129 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -558,9 +558,8 @@ int GetNumCPUsImpl() { int GetNumCPUs() { const int num_cpus = GetNumCPUsImpl(); if (num_cpus < 1) { - PrintErrorAndDie( - "Unable to extract number of CPUs. If your platform uses " - "/proc/cpuinfo, custom support may need to be added."); + std::cerr << "Unable to extract number of CPUs. If your platform uses " + "/proc/cpuinfo, custom support may need to be added.\n"; } return num_cpus; } From 4b184d47a41ed13c6d985b5a7b06498aa5aebaf3 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 17 Jul 2024 16:47:54 +0100 Subject: [PATCH 239/561] update actions/checkout to v4 --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index e3e321752d..b49800629b 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -16,7 +16,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: lukka/get-cmake@latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 97e4d8ea63..319d42d87e 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -17,7 +17,7 @@ jobs: os: [ubuntu-22.04, ubuntu-20.04] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 95e0482aea..d05300db06 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -23,7 +23,7 @@ jobs: lib: ['shared', 'static'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: lukka/get-cmake@latest @@ -87,7 +87,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: lukka/get-cmake@latest @@ -129,7 +129,7 @@ jobs: - static steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Base Dependencies uses: msys2/setup-msys2@v2 diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 328fe36cc7..c790a5a552 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: DoozyX/clang-format-lint-action@v0.13 with: source: './include/benchmark ./src ./test' diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 2eaab9c1e2..558375e3ae 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index da92c46a2d..40c1cb4ebc 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Installing build dependencies run: | diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 86cccf4102..499215331a 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -18,7 +18,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: configure msan env if: matrix.sanitizer == 'msan' From ad2b1c9ed1ec3120fdf68ad9877ab20681ceb09d Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 17 Jul 2024 16:49:12 +0100 Subject: [PATCH 240/561] clang format yet again --- include/benchmark/benchmark.h | 2 +- src/sysinfo.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index dc87676832..7dd72e27bc 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -674,7 +674,7 @@ class Counter { Counter(double v = 0., Flags f = kDefaults, OneK k = kIs1000) : value(v), flags(f), oneK(k) {} - BENCHMARK_ALWAYS_INLINE operator double const&() const { return value; } + BENCHMARK_ALWAYS_INLINE operator double const &() const { return value; } BENCHMARK_ALWAYS_INLINE operator double&() { return value; } }; diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 4638641129..a153b20cf3 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -120,7 +120,7 @@ struct ValueUnion { explicit ValueUnion(std::size_t buff_size) : size(sizeof(DataT) + buff_size), - buff(::new(std::malloc(size)) DataT(), &std::free) {} + buff(::new (std::malloc(size)) DataT(), &std::free) {} ValueUnion(ValueUnion&& other) = default; From a6ad7fbbdc2e14fab82bb8a6d27760d700198cbf Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 18 Jul 2024 11:13:04 +0100 Subject: [PATCH 241/561] preparing for v1.8.5 --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 77eb30a3ea..216c1c9212 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.10...3.22) -project (benchmark VERSION 1.8.4 LANGUAGES CXX) +project (benchmark VERSION 1.8.5 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 0624a34f01..8b98a7a027 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.8.4", + version = "1.8.5", ) bazel_dep(name = "bazel_skylib", version = "1.5.0") From 64b5d8cd111721e4e3e0174825b04eb95309df96 Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Thu, 18 Jul 2024 11:54:02 -0400 Subject: [PATCH 242/561] Update benchmark Python bindings for nanobind 2.0, and update to nanobind 2.0. (#1817) Incorporates the nanobind_bazel change from https://github.com/google/benchmark/pull/1795. nanobind 2.0 reworked the nanobind::enum_ class so it uses a real Python enum or intenum rather than its previous hand-rolled implementation. https://nanobind.readthedocs.io/en/latest/changelog.html#version-2-0-0-may-23-2024 As a consequence of that change, nanobind now checks when casting an integer to a enum value that the integer corresponds to a valid enum. Counter::Flags is a bitmask, and many combinations are not valid enum members. This change: a) sets nb::is_arithmetic(), which means Counter::Flags becomes an IntEnum that can be freely cast to an integer. b) defines the | operator for flags to return an integer, not an enum, avoiding the error. c) changes Counter's constructor to accept an int, not a Counter::Flags enum. Since Counter::Flags is an IntEnum now, it can be freely coerced to an int. If https://github.com/wjakob/nanobind/pull/599 is merged into nanobind, then we can perhaps use a flag enum here instead. --- MODULE.bazel | 2 +- bindings/python/google_benchmark/benchmark.cc | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 8b98a7a027..e368e325c7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -38,4 +38,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "1.0.0", dev_dependency = True) +bazel_dep(name = "nanobind_bazel", version = "2.0.0", dev_dependency = True) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index f44476901c..64ffb92b48 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -118,7 +118,7 @@ NB_MODULE(_benchmark, m) { using benchmark::Counter; nb::class_ py_counter(m, "Counter"); - nb::enum_(py_counter, "Flags") + nb::enum_(py_counter, "Flags", nb::is_arithmetic()) .value("kDefaults", Counter::Flags::kDefaults) .value("kIsRate", Counter::Flags::kIsRate) .value("kAvgThreads", Counter::Flags::kAvgThreads) @@ -130,7 +130,9 @@ NB_MODULE(_benchmark, m) { .value("kAvgIterationsRate", Counter::Flags::kAvgIterationsRate) .value("kInvert", Counter::Flags::kInvert) .export_values() - .def(nb::self | nb::self); + .def("__or__", [](Counter::Flags a, Counter::Flags b) { + return static_cast(a) | static_cast(b); + }); nb::enum_(py_counter, "OneK") .value("kIs1000", Counter::OneK::kIs1000) @@ -138,10 +140,15 @@ NB_MODULE(_benchmark, m) { .export_values(); py_counter - .def(nb::init(), - nb::arg("value") = 0., nb::arg("flags") = Counter::kDefaults, - nb::arg("k") = Counter::kIs1000) - .def("__init__", ([](Counter *c, double value) { new (c) Counter(value); })) + .def( + "__init__", + [](Counter* c, double value, int flags, Counter::OneK oneK) { + new (c) Counter(value, static_cast(flags), oneK); + }, + nb::arg("value") = 0., nb::arg("flags") = Counter::kDefaults, + nb::arg("k") = Counter::kIs1000) + .def("__init__", + ([](Counter* c, double value) { new (c) Counter(value); })) .def_rw("value", &Counter::value) .def_rw("flags", &Counter::flags) .def_rw("oneK", &Counter::oneK) From df44bf7187fb5df0029979ff5a6d3cdd2f25eb59 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 23 Jul 2024 15:49:06 +0200 Subject: [PATCH 243/561] Revert to token authentication for PyPI wheel uploads (#1819) Until the PyPI account is recovered, it should be possible to upload wheels with the GitHub secrets that were previously used. Changes the PyPI upload action sourcing to point to the v1 stable release branch, which receives rolling updates and is the canonical way of including the wheel publishing action. Uploading will probably need another release, because setuptools_scm needs to produce a clean tag that the PyPI API allows as an upload. --- .github/workflows/wheels.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 591d709fba..1a00069e64 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -81,10 +81,11 @@ jobs: name: Publish google-benchmark wheels to PyPI needs: [merge_wheels] runs-on: ubuntu-latest - permissions: - id-token: write steps: - uses: actions/download-artifact@v4 with: path: dist - - uses: pypa/gh-action-pypi-publish@v1.8.14 + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_PASSWORD }} From fa236ed6e6dea36dbc4982ffcca2945281e4433c Mon Sep 17 00:00:00 2001 From: Devon Loehr Date: Wed, 24 Jul 2024 08:12:04 -0400 Subject: [PATCH 244/561] Suppress invalid-offsetof warning for clang (#1821) For several compilers, `benchmark.cc` suppresses a warning regarding its use of `offsetof`. This merely extends that suppression to cover clang as well. --- src/benchmark.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 374c5141c9..2d085447b0 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -207,7 +207,7 @@ State::State(std::string name, IterationCount max_iters, #if defined(__INTEL_COMPILER) #pragma warning push #pragma warning(disable : 1875) -#elif defined(__GNUC__) +#elif defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Winvalid-offsetof" #endif @@ -225,7 +225,7 @@ State::State(std::string name, IterationCount max_iters, offsetof(State, skipped_) <= (cache_line_size - sizeof(skipped_)), ""); #if defined(__INTEL_COMPILER) #pragma warning pop -#elif defined(__GNUC__) +#elif defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop #endif #if defined(__NVCC__) From 378fe693a1ef51500db21b11ff05a8018c5f0e55 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:25:32 +0100 Subject: [PATCH 245/561] Use log2 now that NDK requires at least API 21 which includes it. (#1822) Fixes #1820 --- src/complexity.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/complexity.cc b/src/complexity.cc index eee3122646..63acd504d7 100644 --- a/src/complexity.cc +++ b/src/complexity.cc @@ -27,7 +27,6 @@ namespace benchmark { // Internal function to calculate the different scalability forms BigOFunc* FittingCurve(BigO complexity) { - static const double kLog2E = 1.44269504088896340736; switch (complexity) { case oN: return [](IterationCount n) -> double { return static_cast(n); }; @@ -36,15 +35,12 @@ BigOFunc* FittingCurve(BigO complexity) { case oNCubed: return [](IterationCount n) -> double { return std::pow(n, 3); }; case oLogN: - /* Note: can't use log2 because Android's GNU STL lacks it */ - return [](IterationCount n) { - return kLog2E * std::log(static_cast(n)); + return [](IterationCount n) -> double { + return std::log2(static_cast(n)); }; case oNLogN: - /* Note: can't use log2 because Android's GNU STL lacks it */ - return [](IterationCount n) { - return kLog2E * static_cast(n) * - std::log(static_cast(n)); + return [](IterationCount n) -> double { + return static_cast(n) * std::log2(static_cast(n)); }; case o1: default: From cfb7e0a330ddcaed143c3bb550348833f5af875e Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Tue, 30 Jul 2024 15:09:31 +0200 Subject: [PATCH 246/561] Update libs into .pre-commit-config.yaml (#1825) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a019caf416..99976d9459 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,14 +5,14 @@ repos: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 + rev: v1.11.0 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.5 + rev: v0.4.10 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] - - id: ruff-format \ No newline at end of file + - id: ruff-format From ac80572f17a2f929a680c2d26a4c8839a8e2933f Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Tue, 30 Jul 2024 16:05:08 +0200 Subject: [PATCH 247/561] Update nanobind into benchmark_deps.bzl (#1826) * Update nanobind into benchmark_deps.bzl * Update benchmark_deps.bzl --- bazel/benchmark_deps.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index 4fb45a538d..cb908cd514 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -45,7 +45,7 @@ def benchmark_deps(): new_git_repository( name = "nanobind", remote = "https://github.com/wjakob/nanobind.git", - tag = "v1.8.0", + tag = "v1.9.2", build_file = "@//bindings/python:nanobind.BUILD", recursive_init_submodules = True, ) From 25e5c52a112a56acdc37cace73025f7327f03be7 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 30 Jul 2024 16:49:33 +0200 Subject: [PATCH 248/561] Bump nanobind-bazel to v2.1.0, add stubgen target (#1824) Adds a stub file for the `google_benchmark._benchmark` submodule, generated with the new `nanobind_stubgen` rule released in nanobind_bazel v2.1.0. Tweaks the setup.py logic a little bit to package stub files with the rest of the build artifacts. Also explicitly adds the generated stub and marker files to the list of package data artifacts. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- MODULE.bazel | 2 +- bindings/python/google_benchmark/BUILD | 8 +++++- setup.py | 38 ++++++++++++++++++++------ 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index e368e325c7..4210ea0be2 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -38,4 +38,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "2.0.0", dev_dependency = True) +bazel_dep(name = "nanobind_bazel", version = "2.1.0", dev_dependency = True) diff --git a/bindings/python/google_benchmark/BUILD b/bindings/python/google_benchmark/BUILD index 0c8e3c103f..30e389337d 100644 --- a/bindings/python/google_benchmark/BUILD +++ b/bindings/python/google_benchmark/BUILD @@ -1,4 +1,4 @@ -load("@nanobind_bazel//:build_defs.bzl", "nanobind_extension") +load("@nanobind_bazel//:build_defs.bzl", "nanobind_extension", "nanobind_stubgen") py_library( name = "google_benchmark", @@ -15,6 +15,12 @@ nanobind_extension( deps = ["//:benchmark"], ) +nanobind_stubgen( + name = "benchmark_stubgen", + marker_file = "bindings/python/google_benchmark/py.typed", + module = ":_benchmark", +) + py_test( name = "example", srcs = ["example.py"], diff --git a/setup.py b/setup.py index 40cdc8d339..d171476f7e 100644 --- a/setup.py +++ b/setup.py @@ -99,7 +99,7 @@ def bazel_build(self, ext: BazelExtension) -> None: bazel_argv = [ "bazel", - "build", + "run", ext.bazel_target, f"--symlink_prefix={temp_path / 'bazel-'}", f"--compilation_mode={'dbg' if self.debug else 'opt'}", @@ -127,20 +127,42 @@ def bazel_build(self, ext: BazelExtension) -> None: else: suffix = ".abi3.so" if ext.py_limited_api else ".so" - ext_name = ext.target_name + suffix - ext_bazel_bin_path = temp_path / "bazel-bin" / ext.relpath / ext_name - ext_dest_path = Path(self.get_ext_fullpath(ext.name)).with_name( - ext_name - ) - shutil.copyfile(ext_bazel_bin_path, ext_dest_path) + # copy the Bazel build artifacts into setuptools' libdir, + # from where the wheel is built. + pkgname = "google_benchmark" + pythonroot = Path("bindings") / "python" / "google_benchmark" + srcdir = temp_path / "bazel-bin" / pythonroot + libdir = Path(self.build_lib) / pkgname + for root, dirs, files in os.walk(srcdir, topdown=True): + # exclude runfiles directories and children. + dirs[:] = [d for d in dirs if "runfiles" not in d] + + for f in files: + print(f) + fp = Path(f) + should_copy = False + # we do not want the bare .so file included + # when building for ABI3, so we require a + # full and exact match on the file extension. + if "".join(fp.suffixes) == suffix: + should_copy = True + elif fp.suffix == ".pyi": + should_copy = True + elif Path(root) == srcdir and f == "py.typed": + # copy py.typed, but only at the package root. + should_copy = True + + if should_copy: + shutil.copyfile(root / fp, libdir / fp) setuptools.setup( cmdclass=dict(build_ext=BuildBazelExtension), + package_data={"google_benchmark": ["py.typed", "*.pyi"]}, ext_modules=[ BazelExtension( name="google_benchmark._benchmark", - bazel_target="//bindings/python/google_benchmark:_benchmark", + bazel_target="//bindings/python/google_benchmark:benchmark_stubgen", py_limited_api=py_limited_api, ) ], From ebb5e3922dd1909c2fff4057ff45c39590645d14 Mon Sep 17 00:00:00 2001 From: xdje42 Date: Thu, 1 Aug 2024 00:42:41 -0700 Subject: [PATCH 249/561] Move ProfilerManager Start/Stop routines closer to actual benchmark #1807 (#1818) Previously, the Start/Stop routines were called before the benchmark function was called and after it returned. However, what we really want is for them to be called within the core of the benchmark: for (auto _ : state) { // This is what we want traced, not the entire BM_foo function. } --- include/benchmark/benchmark.h | 4 +++- src/benchmark.cc | 10 ++++++++-- src/benchmark_api_internal.cc | 9 +++++---- src/benchmark_api_internal.h | 3 ++- src/benchmark_runner.cc | 21 ++++++++++++--------- test/profiler_manager_test.cc | 13 ++++++++++--- 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 7dd72e27bc..4cdb4515cb 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1004,7 +1004,8 @@ class BENCHMARK_EXPORT State { State(std::string name, IterationCount max_iters, const std::vector& ranges, int thread_i, int n_threads, internal::ThreadTimer* timer, internal::ThreadManager* manager, - internal::PerfCountersMeasurement* perf_counters_measurement); + internal::PerfCountersMeasurement* perf_counters_measurement, + ProfilerManager* profiler_manager); void StartKeepRunning(); // Implementation of KeepRunning() and KeepRunningBatch(). @@ -1019,6 +1020,7 @@ class BENCHMARK_EXPORT State { internal::ThreadTimer* const timer_; internal::ThreadManager* const manager_; internal::PerfCountersMeasurement* const perf_counters_measurement_; + ProfilerManager* const profiler_manager_; friend class internal::BenchmarkInstance; }; diff --git a/src/benchmark.cc b/src/benchmark.cc index 2d085447b0..b7767bd00a 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -168,7 +168,8 @@ void UseCharPointer(char const volatile* const v) { State::State(std::string name, IterationCount max_iters, const std::vector& ranges, int thread_i, int n_threads, internal::ThreadTimer* timer, internal::ThreadManager* manager, - internal::PerfCountersMeasurement* perf_counters_measurement) + internal::PerfCountersMeasurement* perf_counters_measurement, + ProfilerManager* profiler_manager) : total_iterations_(0), batch_leftover_(0), max_iterations(max_iters), @@ -182,7 +183,8 @@ State::State(std::string name, IterationCount max_iters, threads_(n_threads), timer_(timer), manager_(manager), - perf_counters_measurement_(perf_counters_measurement) { + perf_counters_measurement_(perf_counters_measurement), + profiler_manager_(profiler_manager) { BM_CHECK(max_iterations != 0) << "At least one iteration must be run"; BM_CHECK_LT(thread_index_, threads_) << "thread_index must be less than threads"; @@ -302,6 +304,8 @@ void State::StartKeepRunning() { BM_CHECK(!started_ && !finished_); started_ = true; total_iterations_ = skipped() ? 0 : max_iterations; + if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) + profiler_manager_->AfterSetupStart(); manager_->StartStopBarrier(); if (!skipped()) ResumeTiming(); } @@ -315,6 +319,8 @@ void State::FinishKeepRunning() { total_iterations_ = 0; finished_ = true; manager_->StartStopBarrier(); + if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) + profiler_manager_->BeforeTeardownStop(); } namespace internal { diff --git a/src/benchmark_api_internal.cc b/src/benchmark_api_internal.cc index 286f986530..4b569d7982 100644 --- a/src/benchmark_api_internal.cc +++ b/src/benchmark_api_internal.cc @@ -92,9 +92,10 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx, State BenchmarkInstance::Run( IterationCount iters, int thread_id, internal::ThreadTimer* timer, internal::ThreadManager* manager, - internal::PerfCountersMeasurement* perf_counters_measurement) const { + internal::PerfCountersMeasurement* perf_counters_measurement, + ProfilerManager* profiler_manager) const { State st(name_.function_name, iters, args_, thread_id, threads_, timer, - manager, perf_counters_measurement); + manager, perf_counters_measurement, profiler_manager); benchmark_.Run(st); return st; } @@ -102,7 +103,7 @@ State BenchmarkInstance::Run( void BenchmarkInstance::Setup() const { if (setup_) { State st(name_.function_name, /*iters*/ 1, args_, /*thread_id*/ 0, threads_, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); setup_(st); } } @@ -110,7 +111,7 @@ void BenchmarkInstance::Setup() const { void BenchmarkInstance::Teardown() const { if (teardown_) { State st(name_.function_name, /*iters*/ 1, args_, /*thread_id*/ 0, threads_, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); teardown_(st); } } diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h index 94f516531b..659a71440e 100644 --- a/src/benchmark_api_internal.h +++ b/src/benchmark_api_internal.h @@ -44,7 +44,8 @@ class BenchmarkInstance { State Run(IterationCount iters, int thread_id, internal::ThreadTimer* timer, internal::ThreadManager* manager, - internal::PerfCountersMeasurement* perf_counters_measurement) const; + internal::PerfCountersMeasurement* perf_counters_measurement, + ProfilerManager* profiler_manager) const; private: BenchmarkName name_; diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 3a8c3076a4..19f468af94 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -125,14 +125,15 @@ BenchmarkReporter::Run CreateRunReport( // Adds the stats collected for the thread into manager->results. void RunInThread(const BenchmarkInstance* b, IterationCount iters, int thread_id, ThreadManager* manager, - PerfCountersMeasurement* perf_counters_measurement) { + PerfCountersMeasurement* perf_counters_measurement, + ProfilerManager* profiler_manager) { internal::ThreadTimer timer( b->measure_process_cpu_time() ? internal::ThreadTimer::CreateProcessCpuTime() : internal::ThreadTimer::Create()); - State st = - b->Run(iters, thread_id, &timer, manager, perf_counters_measurement); + State st = b->Run(iters, thread_id, &timer, manager, + perf_counters_measurement, profiler_manager); BM_CHECK(st.skipped() || st.iterations() >= st.max_iterations) << "Benchmark returned before State::KeepRunning() returned false!"; { @@ -268,12 +269,14 @@ BenchmarkRunner::IterationResults BenchmarkRunner::DoNIterations() { // Run all but one thread in separate threads for (std::size_t ti = 0; ti < pool.size(); ++ti) { pool[ti] = std::thread(&RunInThread, &b, iters, static_cast(ti + 1), - manager.get(), perf_counters_measurement_ptr); + manager.get(), perf_counters_measurement_ptr, + /*profiler_manager=*/nullptr); } // And run one thread here directly. // (If we were asked to run just one thread, we don't create new threads.) // Yes, we need to do this here *after* we start the separate threads. - RunInThread(&b, iters, 0, manager.get(), perf_counters_measurement_ptr); + RunInThread(&b, iters, 0, manager.get(), perf_counters_measurement_ptr, + /*profiler_manager=*/nullptr); // The main thread has finished. Now let's wait for the other threads. manager->WaitForAllThreads(); @@ -415,7 +418,8 @@ MemoryManager::Result* BenchmarkRunner::RunMemoryManager( manager.reset(new internal::ThreadManager(1)); b.Setup(); RunInThread(&b, memory_iterations, 0, manager.get(), - perf_counters_measurement_ptr); + perf_counters_measurement_ptr, + /*profiler_manager=*/nullptr); manager->WaitForAllThreads(); manager.reset(); b.Teardown(); @@ -429,11 +433,10 @@ void BenchmarkRunner::RunProfilerManager() { std::unique_ptr manager; manager.reset(new internal::ThreadManager(1)); b.Setup(); - profiler_manager->AfterSetupStart(); RunInThread(&b, profile_iterations, 0, manager.get(), - /*perf_counters_measurement_ptr=*/nullptr); + /*perf_counters_measurement_ptr=*/nullptr, + /*profiler_manager=*/profiler_manager); manager->WaitForAllThreads(); - profiler_manager->BeforeTeardownStop(); manager.reset(); b.Teardown(); } diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc index 1b3e36c37f..3b08a60d1d 100644 --- a/test/profiler_manager_test.cc +++ b/test/profiler_manager_test.cc @@ -6,8 +6,12 @@ #include "output_test.h" class TestProfilerManager : public benchmark::ProfilerManager { - void AfterSetupStart() override {} - void BeforeTeardownStop() override {} + public: + void AfterSetupStart() override { ++start_called; } + void BeforeTeardownStop() override { ++stop_called; } + + int start_called = 0; + int stop_called = 0; }; void BM_empty(benchmark::State& state) { @@ -35,9 +39,12 @@ ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"}, ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}}); int main(int argc, char* argv[]) { - std::unique_ptr pm(new TestProfilerManager()); + std::unique_ptr pm(new TestProfilerManager()); benchmark::RegisterProfilerManager(pm.get()); RunOutputTests(argc, argv); benchmark::RegisterProfilerManager(nullptr); + + assert(pm->start_called == 1); + assert(pm->stop_called == 1); } From 7971a63070dcfa848489cd2c6cdcbdefe8cdb000 Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Fri, 2 Aug 2024 11:56:57 +0200 Subject: [PATCH 250/561] Cache upd (#1830) * Update bazel.yml switch to node20 updated actions/cache to v4 * Update pre-commit.yml switch to node20 updated actions/cache to v4 --- .github/workflows/bazel.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index a669cda84c..b50a8f6464 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 - name: mount bazel cache - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: bazel-cache with: diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 5d65b9948f..8b217e981d 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -27,7 +27,7 @@ jobs: - name: Install dependencies run: python -m pip install ".[dev]" - name: Cache pre-commit tools - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ${{ env.MYPY_CACHE_DIR }} From ef73a30083ccd4eb1ad6e67a68b23163bf195561 Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Fri, 2 Aug 2024 12:06:00 +0200 Subject: [PATCH 251/561] Update clang-format-lint-action (#1829) Colorize output in github action Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/clang-format-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index c790a5a552..8f089dc8dc 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: DoozyX/clang-format-lint-action@v0.13 + - uses: DoozyX/clang-format-lint-action@v0.15 with: source: './include/benchmark ./src ./test' extensions: 'h,cc' From b884717437fc468929cd47ca6a374005357ff18e Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 5 Aug 2024 18:05:40 +0900 Subject: [PATCH 252/561] chore: update perf_counters.cc (#1831) peformance -> performance --- src/perf_counters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index fa1cbb0e8f..fc9586b716 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -218,7 +218,7 @@ PerfCounters PerfCounters::Create( GetErrorLogInstance() << "***WARNING*** Failed to start counters. " "Claring out all counters.\n"; - // Close all peformance counters + // Close all performance counters for (int id : counter_ids) { ::close(id); } From a008bf82f4aa5ad6605622040c7b2fe7512dc0c7 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:12:02 +0100 Subject: [PATCH 253/561] Ensure reported Time is walltime by removing spurious scaling by threads (#1836) * change the default to not scale --- src/benchmark_runner.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 19f468af94..a38093937a 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -292,12 +292,6 @@ BenchmarkRunner::IterationResults BenchmarkRunner::DoNIterations() { // And get rid of the manager. manager.reset(); - // Adjust real/manual time stats since they were reported per thread. - i.results.real_time_used /= b.threads(); - i.results.manual_time_used /= b.threads(); - // If we were measuring whole-process CPU usage, adjust the CPU time too. - if (b.measure_process_cpu_time()) i.results.cpu_time_used /= b.threads(); - BM_VLOG(2) << "Ran in " << i.results.cpu_time_used << "/" << i.results.real_time_used << "\n"; From 12235e24652fc7f809373e7c11a5f73c5763fc4c Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Fri, 16 Aug 2024 11:08:15 +0100 Subject: [PATCH 254/561] v1.9.0 --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 216c1c9212..40ff75844e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.10...3.22) -project (benchmark VERSION 1.8.5 LANGUAGES CXX) +project (benchmark VERSION 1.9.0 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 4210ea0be2..e4f170c83d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.8.5", + version = "1.9.0", ) bazel_dep(name = "bazel_skylib", version = "1.5.0") From ec3dc37b6035aa5431ea60aa1d54fdc5f82ec701 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Fri, 16 Aug 2024 11:56:56 +0100 Subject: [PATCH 255/561] separate wheel versions in an effort to avoid timeouts --- .github/workflows/wheels.yml | 58 ++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 1a00069e64..83c5bbf81e 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -46,10 +46,62 @@ jobs: with: platforms: all - - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.17 + - name: Build 3.8 wheels on ${{ matrix.os }} using cibuildwheel + uses: pypa/cibuildwheel@v2.20 env: - CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-*" + CIBW_BUILD: "cp38-*" + CIBW_SKIP: "*-musllinux_*" + CIBW_TEST_SKIP: "cp38-macosx_*:arm64" + CIBW_ARCHS_LINUX: auto64 aarch64 + CIBW_ARCHS_WINDOWS: auto64 + CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh + # Grab the rootless Bazel installation inside the container. + CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin + CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py + + - name: Build 3.9 wheels on ${{ matrix.os }} using cibuildwheel + uses: pypa/cibuildwheel@v2.20 + env: + CIBW_BUILD: "cp39-*" + CIBW_SKIP: "*-musllinux_*" + CIBW_TEST_SKIP: "cp38-macosx_*:arm64" + CIBW_ARCHS_LINUX: auto64 aarch64 + CIBW_ARCHS_WINDOWS: auto64 + CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh + # Grab the rootless Bazel installation inside the container. + CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin + CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py + + - name: Build 3.10 wheels on ${{ matrix.os }} using cibuildwheel + uses: pypa/cibuildwheel@v2.20 + env: + CIBW_BUILD: "cp310-*" + CIBW_SKIP: "*-musllinux_*" + CIBW_TEST_SKIP: "cp38-macosx_*:arm64" + CIBW_ARCHS_LINUX: auto64 aarch64 + CIBW_ARCHS_WINDOWS: auto64 + CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh + # Grab the rootless Bazel installation inside the container. + CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin + CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py + + - name: Build 3.11 wheels on ${{ matrix.os }} using cibuildwheel + uses: pypa/cibuildwheel@v2.20 + env: + CIBW_BUILD: "cp311-*" + CIBW_SKIP: "*-musllinux_*" + CIBW_TEST_SKIP: "cp38-macosx_*:arm64" + CIBW_ARCHS_LINUX: auto64 aarch64 + CIBW_ARCHS_WINDOWS: auto64 + CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh + # Grab the rootless Bazel installation inside the container. + CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin + CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py + + - name: Build 3.12 wheels on ${{ matrix.os }} using cibuildwheel + uses: pypa/cibuildwheel@v2.20 + env: + CIBW_BUILD: "cp312-*" CIBW_SKIP: "*-musllinux_*" CIBW_TEST_SKIP: "cp38-macosx_*:arm64" CIBW_ARCHS_LINUX: auto64 aarch64 From 437fea4b549a449ac319618552981cb328f1aaf4 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Fri, 16 Aug 2024 16:32:48 +0200 Subject: [PATCH 256/561] Fix Python manual timing example (#1722) According to the user guide, when manual timing, it is necessary to explicit it by using the `UseManualTime` function. Its equivalent in Python is use_manual_time(). This function was not called in the example. It is possible to verify that the use of this function has an impact on the measure by adding another `time.sleep(0.01)` at the end of the iteration. There is a x2 difference depending on whether `use_manual_time()` is used or not. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- bindings/python/google_benchmark/example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/python/google_benchmark/example.py b/bindings/python/google_benchmark/example.py index b5b2f88ff3..b92245ea67 100644 --- a/bindings/python/google_benchmark/example.py +++ b/bindings/python/google_benchmark/example.py @@ -61,6 +61,7 @@ def skipped(state): @benchmark.register +@benchmark.option.use_manual_time() def manual_timing(state): while state: # Manually count Python CPU time From 6126d2a2052bb48d3472ac0468ade50397d393c5 Mon Sep 17 00:00:00 2001 From: Chris Kennelly Date: Fri, 16 Aug 2024 11:10:18 -0400 Subject: [PATCH 257/561] Align benchmark::State to a cacheline. (#1230) * Align benchmark::State to a cacheline. This can avoid interference with neighboring objects and stabilize benchmark results. * separate cachline definition from alignment attribute macro Co-authored-by: Roman Lebedev --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> Co-authored-by: Roman Lebedev --- include/benchmark/benchmark.h | 43 +++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 4cdb4515cb..66f34867d7 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -290,11 +290,50 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #define BENCHMARK_OVERRIDE #endif +#if defined(__GNUC__) +// Determine the cacheline size based on architecture +#if defined(__i386__) || defined(__x86_64__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#elif defined(__powerpc64__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 128 +#elif defined(__aarch64__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#elif defined(__arm__) +// Cache line sizes for ARM: These values are not strictly correct since +// cache line sizes depend on implementations, not architectures. There +// are even implementations with cache line sizes configurable at boot +// time. +#if defined(__ARM_ARCH_5T__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 32 +#elif defined(__ARM_ARCH_7A__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#endif // ARM_ARCH +#endif // arches +#endif // __GNUC__ + +#ifndef BENCHMARK_INTERNAL_CACHELINE_SIZE +// A reasonable default guess. Note that overestimates tend to waste more +// space, while underestimates tend to waste more time. +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#endif + +#if defined(__GNUC__) +// Indicates that the declared object be cache aligned using +// `BENCHMARK_INTERNAL_CACHELINE_SIZE` (see above). +#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED \ + __attribute__((aligned(BENCHMARK_INTERNAL_CACHELINE_SIZE))) +#elif defined(_MSC_VER) +#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED \ + __declspec(align(BENCHMARK_INTERNAL_CACHELINE_SIZE)) +#else +#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED +#endif + #if defined(_MSC_VER) #pragma warning(push) // C4251: needs to have dll-interface to be used by clients of class #pragma warning(disable : 4251) -#endif +#endif // _MSC_VER_ namespace benchmark { class BenchmarkReporter; @@ -759,7 +798,7 @@ enum Skipped // State is passed to a running Benchmark and contains state for the // benchmark to use. -class BENCHMARK_EXPORT State { +class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { public: struct StateIterator; friend struct StateIterator; From c19cfee61e136effb05a7fc8a037b0db3b13bd4c Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Mon, 19 Aug 2024 10:39:37 +0700 Subject: [PATCH 258/561] Fix C4459: Rename a function parameter `profiler_manager` to avoid hiding the global declaration. (#1839) * Fix C4459: Rename a function parameter `profiler_manager` to avoid hiding the global declaration. * Treat warnings as errors for MSVC * disable one warning for MSVC --- CMakeLists.txt | 4 ++++ include/benchmark/benchmark.h | 8 ++++++++ src/benchmark_runner.cc | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40ff75844e..e0cd6962e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,10 @@ if (MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") add_definitions(-D_CRT_SECURE_NO_WARNINGS) + if(BENCHMARK_ENABLE_WERROR) + add_cxx_compiler_flag(-WX) + endif() + if (NOT BENCHMARK_ENABLE_EXCEPTIONS) add_cxx_compiler_flag(-EHs-) add_cxx_compiler_flag(-EHa-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 66f34867d7..53a22247f2 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -796,6 +796,11 @@ enum Skipped } // namespace internal +#if defined(_MSC_VER) +#pragma warning(push) +// C4324: 'benchmark::State': structure was padded due to alignment specifier +#pragma warning(disable : 4324) +#endif // _MSC_VER_ // State is passed to a running Benchmark and contains state for the // benchmark to use. class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { @@ -1063,6 +1068,9 @@ class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { friend class internal::BenchmarkInstance; }; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER_ inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunning() { return KeepRunningInternal(1, /*is_batch=*/false); diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index a38093937a..c658d574ca 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -126,14 +126,14 @@ BenchmarkReporter::Run CreateRunReport( void RunInThread(const BenchmarkInstance* b, IterationCount iters, int thread_id, ThreadManager* manager, PerfCountersMeasurement* perf_counters_measurement, - ProfilerManager* profiler_manager) { + ProfilerManager* profiler_manager_) { internal::ThreadTimer timer( b->measure_process_cpu_time() ? internal::ThreadTimer::CreateProcessCpuTime() : internal::ThreadTimer::Create()); State st = b->Run(iters, thread_id, &timer, manager, - perf_counters_measurement, profiler_manager); + perf_counters_measurement, profiler_manager_); BM_CHECK(st.skipped() || st.iterations() >= st.max_iterations) << "Benchmark returned before State::KeepRunning() returned false!"; { From 986423a62dd174e75282e432e9fbaf921c9c7ccc Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Wed, 4 Sep 2024 18:42:07 +0200 Subject: [PATCH 259/561] Bump oldest supported Python to 3.10, eliminate setuptools-scm (#1842) * Supply MacOS deployment target to delocate, use build+uv frontend This shaves off multiple minutes from the wheel builds alone. Also revert to trusted publishing for wheel uploads as it is now set up. * Bump oldest supported Python to 3.10, eliminate setuptools-scm The version is now a string again, under the same attribute as it was before. This is a pragmatic decision in order to be able to upload wheels again, possibly directly from main. We could in the future also set the Python version to a development version if we want to avoid accidental uploads of `main`. * Add a note on supported Python versions in the docs Also fixes the setuptools failure observed in the latest CI by pinning to the last version before v73 until the problem is identified and resolved. --- .github/workflows/wheels.yml | 73 ++++---------------- .pre-commit-config.yaml | 6 +- bindings/python/google_benchmark/__init__.py | 3 +- bindings/python/google_benchmark/version.py | 7 -- docs/dependencies.md | 6 ++ docs/releasing.md | 19 +++-- pyproject.toml | 25 +++---- setup.py | 1 - 8 files changed, 47 insertions(+), 93 deletions(-) delete mode 100644 bindings/python/google_benchmark/version.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 83c5bbf81e..7544b24758 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -18,7 +18,7 @@ jobs: - name: Install Python 3.12 uses: actions/setup-python@v5 with: - python-version: 3.12 + python-version: "3.12" - run: python -m pip install build - name: Build sdist run: python -m build --sdist @@ -40,68 +40,23 @@ jobs: with: fetch-depth: 0 + - uses: actions/setup-python@v5 + name: Install Python 3.12 + with: + python-version: "3.12" + - run: pip install --upgrade pip uv + - name: Set up QEMU if: runner.os == 'Linux' uses: docker/setup-qemu-action@v3 with: platforms: all - - name: Build 3.8 wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.20 - env: - CIBW_BUILD: "cp38-*" - CIBW_SKIP: "*-musllinux_*" - CIBW_TEST_SKIP: "cp38-macosx_*:arm64" - CIBW_ARCHS_LINUX: auto64 aarch64 - CIBW_ARCHS_WINDOWS: auto64 - CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh - # Grab the rootless Bazel installation inside the container. - CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin - CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py - - - name: Build 3.9 wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.20 - env: - CIBW_BUILD: "cp39-*" - CIBW_SKIP: "*-musllinux_*" - CIBW_TEST_SKIP: "cp38-macosx_*:arm64" - CIBW_ARCHS_LINUX: auto64 aarch64 - CIBW_ARCHS_WINDOWS: auto64 - CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh - # Grab the rootless Bazel installation inside the container. - CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin - CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py - - - name: Build 3.10 wheels on ${{ matrix.os }} using cibuildwheel + - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@v2.20 env: - CIBW_BUILD: "cp310-*" - CIBW_SKIP: "*-musllinux_*" - CIBW_TEST_SKIP: "cp38-macosx_*:arm64" - CIBW_ARCHS_LINUX: auto64 aarch64 - CIBW_ARCHS_WINDOWS: auto64 - CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh - # Grab the rootless Bazel installation inside the container. - CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin - CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py - - - name: Build 3.11 wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.20 - env: - CIBW_BUILD: "cp311-*" - CIBW_SKIP: "*-musllinux_*" - CIBW_TEST_SKIP: "cp38-macosx_*:arm64" - CIBW_ARCHS_LINUX: auto64 aarch64 - CIBW_ARCHS_WINDOWS: auto64 - CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh - # Grab the rootless Bazel installation inside the container. - CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin - CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py - - - name: Build 3.12 wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.20 - env: - CIBW_BUILD: "cp312-*" + CIBW_BUILD: "cp310-* cp311-* cp312-*" + CIBW_BUILD_FRONTEND: "build[uv]" CIBW_SKIP: "*-musllinux_*" CIBW_TEST_SKIP: "cp38-macosx_*:arm64" CIBW_ARCHS_LINUX: auto64 aarch64 @@ -110,6 +65,8 @@ jobs: # Grab the rootless Bazel installation inside the container. CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py + # unused by Bazel, but needed explicitly by delocate on MacOS. + MACOSX_DEPLOYMENT_TARGET: "10.14" - name: Upload Google Benchmark ${{ matrix.os }} wheels uses: actions/upload-artifact@v4 @@ -133,11 +90,11 @@ jobs: name: Publish google-benchmark wheels to PyPI needs: [merge_wheels] runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.action == 'published' + permissions: + id-token: write steps: - uses: actions/download-artifact@v4 with: path: dist - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_PASSWORD }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 99976d9459..ef13c1dabd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 6.4.0 + rev: 7.1.2 hooks: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.0 + rev: v1.11.1 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.10 + rev: v0.6.1 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index c1393b4e58..e7870c854c 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -49,7 +49,8 @@ def my_benchmark(state): oNone as oNone, oNSquared as oNSquared, ) -from google_benchmark.version import __version__ as __version__ + +__version__ = "1.9.0" class __OptionMaker: diff --git a/bindings/python/google_benchmark/version.py b/bindings/python/google_benchmark/version.py deleted file mode 100644 index a324693e2d..0000000000 --- a/bindings/python/google_benchmark/version.py +++ /dev/null @@ -1,7 +0,0 @@ -from importlib.metadata import PackageNotFoundError, version - -try: - __version__ = version("google-benchmark") -except PackageNotFoundError: - # package is not installed - pass diff --git a/docs/dependencies.md b/docs/dependencies.md index 07760e10e3..98ce996391 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -11,3 +11,9 @@ distributions include newer versions, for example: * Ubuntu 20.04 provides CMake 3.16.3 * Debian 11.4 provides CMake 3.18.4 * Ubuntu 22.04 provides CMake 3.22.1 + +## Python + +The Python bindings require Python 3.10+ as of v1.9.0 (2024-08-16) for installation from PyPI. +Building from source for older versions probably still works, though. See the [user guide](python_bindings.md) for details on how to build from source. +The minimum theoretically supported version is Python 3.8, since the used bindings generator (nanobind) only supports Python 3.8+. diff --git a/docs/releasing.md b/docs/releasing.md index 09bf93764d..ab664a8640 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -8,16 +8,24 @@ * `git log $(git describe --abbrev=0 --tags)..HEAD` gives you the list of commits between the last annotated tag and HEAD * Pick the most interesting. -* Create one last commit that updates the version saved in `CMakeLists.txt` and `MODULE.bazel` - to the release version you're creating. (This version will be used if benchmark is installed - from the archive you'll be creating in the next step.) +* Create one last commit that updates the version saved in `CMakeLists.txt`, `MODULE.bazel`, + and `bindings/python/google_benchmark/__init__.py` to the release version you're creating. + (This version will be used if benchmark is installed from the archive you'll be creating + in the next step.) ``` -project (benchmark VERSION 1.8.0 LANGUAGES CXX) +# CMakeLists.txt +project (benchmark VERSION 1.9.0 LANGUAGES CXX) ``` ``` -module(name = "com_github_google_benchmark", version="1.8.0") +# MODULE.bazel +module(name = "com_github_google_benchmark", version="1.9.0") +``` + +``` +# google_benchmark/__init__.py +__version__ = "1.9.0" ``` * Create a release through github's interface @@ -28,4 +36,3 @@ module(name = "com_github_google_benchmark", version="1.8.0") * `git push --force --tags origin` * Confirm that the "Build and upload Python wheels" action runs to completion * Run it manually if it hasn't run. - * IMPORTANT: When re-running manually, make sure to select the newly created `` as the workflow version in the "Run workflow" tab on the GitHub Actions page. diff --git a/pyproject.toml b/pyproject.toml index 62507a8703..14f173f956 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,25 +1,21 @@ [build-system] -requires = ["setuptools", "setuptools-scm[toml]", "wheel"] +requires = ["setuptools<73"] build-backend = "setuptools.build_meta" [project] name = "google_benchmark" description = "A library to benchmark code snippets." -requires-python = ">=3.8" -license = {file = "LICENSE"} +requires-python = ">=3.10" +license = { file = "LICENSE" } keywords = ["benchmark"] -authors = [ - {name = "Google", email = "benchmark-discuss@googlegroups.com"}, -] +authors = [{ name = "Google", email = "benchmark-discuss@googlegroups.com" }] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -29,14 +25,10 @@ classifiers = [ dynamic = ["readme", "version"] -dependencies = [ - "absl-py>=0.7.1", -] +dependencies = ["absl-py>=0.7.1"] [project.optional-dependencies] -dev = [ - "pre-commit>=3.3.3", -] +dev = ["pre-commit>=3.3.3"] [project.urls] Homepage = "https://github.com/google/benchmark" @@ -45,7 +37,7 @@ Repository = "https://github.com/google/benchmark.git" Discord = "https://discord.gg/cz7UX7wKC2" [tool.setuptools] -package-dir = {"" = "bindings/python"} +package-dir = { "" = "bindings/python" } zip-safe = false [tool.setuptools.packages.find] @@ -53,8 +45,7 @@ where = ["bindings/python"] [tool.setuptools.dynamic] readme = { file = "README.md", content-type = "text/markdown" } - -[tool.setuptools_scm] +version = { attr = "google_benchmark.__version__" } [tool.mypy] check_untyped_defs = true diff --git a/setup.py b/setup.py index d171476f7e..1e4c0db761 100644 --- a/setup.py +++ b/setup.py @@ -138,7 +138,6 @@ def bazel_build(self, ext: BazelExtension) -> None: dirs[:] = [d for d in dirs if "runfiles" not in d] for f in files: - print(f) fp = Path(f) should_copy = False # we do not want the bare .so file included From 08fdf6eb84cc8a5b65d84041257c908de5879bf5 Mon Sep 17 00:00:00 2001 From: Richard Cole Date: Thu, 5 Sep 2024 22:28:43 +0100 Subject: [PATCH 260/561] enable the /MP MSVC compiler argument for parallel compilation (#1846) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0cd6962e0..a86a5686ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,7 +147,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) if (MSVC) # Turn compiler warnings up to 11 string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP") add_definitions(-D_CRT_SECURE_NO_WARNINGS) if(BENCHMARK_ENABLE_WERROR) From 72ecc4ea67d89869461c361ad30dc6c13b3f8e47 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:50:52 +0100 Subject: [PATCH 261/561] Added the functionality for a dry run benchmark called through the cli argument --benchmark_dry_run. (#1851) * Added benchmark_dry_run boolean flag to command line options * Dry run logic to exit early and override iterations, repetitions, min time, min warmup time * Changeddry run override logic structure and added dry run to context --------- Co-authored-by: Shaan Co-authored-by: Shaan Mistry <49106143+Shaan-Mistry@users.noreply.github.com> --- src/benchmark.cc | 10 ++++++++++ src/benchmark_runner.cc | 39 ++++++++++++++++++++++++++++----------- src/benchmark_runner.h | 7 ------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index b7767bd00a..2605077444 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -92,6 +92,11 @@ BM_DEFINE_double(benchmark_min_warmup_time, 0.0); // standard deviation of the runs will be reported. BM_DEFINE_int32(benchmark_repetitions, 1); +// If enabled, forces each benchmark to execute exactly one iteration and one +// repetition, bypassing any configured +// MinTime()/MinWarmUpTime()/Iterations()/Repetitions() +BM_DEFINE_bool(benchmark_dry_run, false); + // If set, enable random interleaving of repetitions of all benchmarks. // See http://github.com/google/benchmark/issues/1051 for details. BM_DEFINE_bool(benchmark_enable_random_interleaving, false); @@ -717,6 +722,7 @@ void ParseCommandLineFlags(int* argc, char** argv) { &FLAGS_benchmark_min_warmup_time) || ParseInt32Flag(argv[i], "benchmark_repetitions", &FLAGS_benchmark_repetitions) || + ParseBoolFlag(argv[i], "benchmark_dry_run", &FLAGS_benchmark_dry_run) || ParseBoolFlag(argv[i], "benchmark_enable_random_interleaving", &FLAGS_benchmark_enable_random_interleaving) || ParseBoolFlag(argv[i], "benchmark_report_aggregates_only", @@ -755,6 +761,9 @@ void ParseCommandLineFlags(int* argc, char** argv) { if (FLAGS_benchmark_color.empty()) { PrintUsageAndExit(); } + if (FLAGS_benchmark_dry_run) { + AddCustomContext("dry_run", "true"); + } for (const auto& kv : FLAGS_benchmark_context) { AddCustomContext(kv.first, kv.second); } @@ -783,6 +792,7 @@ void PrintDefaultHelp() { " [--benchmark_min_time=`x` OR `s` ]\n" " [--benchmark_min_warmup_time=]\n" " [--benchmark_repetitions=]\n" + " [--benchmark_dry_run={true|false}]\n" " [--benchmark_enable_random_interleaving={true|false}]\n" " [--benchmark_report_aggregates_only={true|false}]\n" " [--benchmark_display_aggregates_only={true|false}]\n" diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index c658d574ca..463f69fc52 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -58,6 +58,14 @@ namespace benchmark { +BM_DECLARE_bool(benchmark_dry_run); +BM_DECLARE_string(benchmark_min_time); +BM_DECLARE_double(benchmark_min_warmup_time); +BM_DECLARE_int32(benchmark_repetitions); +BM_DECLARE_bool(benchmark_report_aggregates_only); +BM_DECLARE_bool(benchmark_display_aggregates_only); +BM_DECLARE_string(benchmark_perf_counters); + namespace internal { MemoryManager* memory_manager = nullptr; @@ -228,20 +236,29 @@ BenchmarkRunner::BenchmarkRunner( : b(b_), reports_for_family(reports_for_family_), parsed_benchtime_flag(ParseBenchMinTime(FLAGS_benchmark_min_time)), - min_time(ComputeMinTime(b_, parsed_benchtime_flag)), - min_warmup_time((!IsZero(b.min_time()) && b.min_warmup_time() > 0.0) - ? b.min_warmup_time() - : FLAGS_benchmark_min_warmup_time), - warmup_done(!(min_warmup_time > 0.0)), - repeats(b.repetitions() != 0 ? b.repetitions() - : FLAGS_benchmark_repetitions), + min_time(FLAGS_benchmark_dry_run + ? 0 + : ComputeMinTime(b_, parsed_benchtime_flag)), + min_warmup_time( + FLAGS_benchmark_dry_run + ? 0 + : ((!IsZero(b.min_time()) && b.min_warmup_time() > 0.0) + ? b.min_warmup_time() + : FLAGS_benchmark_min_warmup_time)), + warmup_done(FLAGS_benchmark_dry_run ? true : !(min_warmup_time > 0.0)), + repeats(FLAGS_benchmark_dry_run + ? 1 + : (b.repetitions() != 0 ? b.repetitions() + : FLAGS_benchmark_repetitions)), has_explicit_iteration_count(b.iterations() != 0 || parsed_benchtime_flag.tag == BenchTimeType::ITERS), pool(static_cast(b.threads() - 1)), - iters(has_explicit_iteration_count - ? ComputeIters(b_, parsed_benchtime_flag) - : 1), + iters(FLAGS_benchmark_dry_run + ? 1 + : (has_explicit_iteration_count + ? ComputeIters(b_, parsed_benchtime_flag) + : 1)), perf_counters_measurement_ptr(pcm_) { run_results.display_report_aggregates_only = (FLAGS_benchmark_report_aggregates_only || @@ -339,7 +356,7 @@ bool BenchmarkRunner::ShouldReportIterationResults( // Determine if this run should be reported; // Either it has run for a sufficient amount of time // or because an error was reported. - return i.results.skipped_ || + return i.results.skipped_ || FLAGS_benchmark_dry_run || i.iters >= kMaxIterations || // Too many iterations already. i.seconds >= GetMinTimeToApply() || // The elapsed time is large enough. diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index cd34d2d5bb..6e5ceb31e0 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -25,13 +25,6 @@ namespace benchmark { -BM_DECLARE_string(benchmark_min_time); -BM_DECLARE_double(benchmark_min_warmup_time); -BM_DECLARE_int32(benchmark_repetitions); -BM_DECLARE_bool(benchmark_report_aggregates_only); -BM_DECLARE_bool(benchmark_display_aggregates_only); -BM_DECLARE_string(benchmark_perf_counters); - namespace internal { extern MemoryManager* memory_manager; From 3fd1e6a7aee12e6878d7e039f947ea81140b4f5a Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Fri, 13 Sep 2024 10:06:24 +0100 Subject: [PATCH 262/561] add dry run docs --- docs/user_guide.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/user_guide.md b/docs/user_guide.md index e38262099d..64566f1f37 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -167,6 +167,13 @@ line interface or by setting environment variables before execution. For every prevails). A complete list of CLI options is available running benchmarks with the `--help` switch. +### Dry runs + +To confirm that benchmarks can run successfully without needing to wait for +multiple repetitions and iterations, the `--benchmark_dry_run` flag can be +used. This will run the benchmarks as normal, but for 1 iteration and 1 +repetition only. + ## Running a Subset of Benchmarks From 23d8c1e58941ca48b4ef67595addaf78412109ef Mon Sep 17 00:00:00 2001 From: Alfredo Daniel Esponda Cervantes <92197886+aespondac@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:56:16 -0600 Subject: [PATCH 263/561] Version string correction in pkg-config files (#1858) Co-authored-by: Alfredo Daniel Esponda Cervantes <92197886+DanEC1211@users.noreply.github.com> --- cmake/benchmark.pc.in | 2 +- cmake/benchmark_main.pc.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/benchmark.pc.in b/cmake/benchmark.pc.in index 043f2fc759..bbed29d1eb 100644 --- a/cmake/benchmark.pc.in +++ b/cmake/benchmark.pc.in @@ -5,7 +5,7 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: Google microbenchmark framework -Version: @VERSION@ +Version: @NORMALIZED_VERSION@ Libs: -L${libdir} -lbenchmark Libs.private: -lpthread @BENCHMARK_PRIVATE_LINK_LIBRARIES@ diff --git a/cmake/benchmark_main.pc.in b/cmake/benchmark_main.pc.in index a90f3cd060..e9d81a05ee 100644 --- a/cmake/benchmark_main.pc.in +++ b/cmake/benchmark_main.pc.in @@ -2,6 +2,6 @@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ Name: @PROJECT_NAME@ Description: Google microbenchmark framework (with main() function) -Version: @VERSION@ +Version: @NORMALIZED_VERSION@ Requires: benchmark Libs: -L${libdir} -lbenchmark_main From 24e0bd827a8bec8121b128b0634cb34402fb3259 Mon Sep 17 00:00:00 2001 From: Devon Loehr Date: Wed, 2 Oct 2024 04:40:03 -0400 Subject: [PATCH 264/561] Add enum value from newest Windows SDK (#1859) * Add enum value from newest Windows SDK Windows SDK version 10.0.26100.0 adds a cache type value, `CacheUnknown`. This adds a case for that type to `sysinfo.cc`, which will otherwise complain about the switch statement being non-exhaustive when building with the new SDK. Since the value doesn't exist in prior SDK versions, we only add the case conditionally. The condition can be removed if we ever decide to bump up the required SDK version. * Fix SDK version macro Make sure the version macro we're using for the SDK is properly indicative of version 10.0.26100.0. Also fix formatting complains from the linter. * Add space to satisfy formatter Formatter insists on two space before a comment after a macro... * Change preprocessor condition Try detecting the current SDK version in a slightly different way. * Replace NTDDI_WIN11_GE with its value Undefined constants are treated as 0 by the preprocessor, which causes the check to trivially return true for previous SDK versions. Replace the constant with its value (from the newest SDK version) instead, --- src/sysinfo.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index a153b20cf3..7148598264 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -353,6 +353,12 @@ std::vector GetCacheSizesWindows() { C.size = static_cast(cache.Size); C.type = "Unknown"; switch (cache.Type) { +// Windows SDK version >= 10.0.26100.0 +// 0x0A000010 is the value of NTDDI_WIN11_GE +#if NTDDI_VERSION >= 0x0A000010 + case CacheUnknown: + break; +#endif case CacheUnified: C.type = "Unified"; break; From 0c998f7cc4137fcd8da8e0c1887689a19fa19ecf Mon Sep 17 00:00:00 2001 From: Alecto Irene Perez Date: Thu, 10 Oct 2024 18:02:36 -0400 Subject: [PATCH 265/561] Fix spurious warning 'misc-use-anonymous-namespace' (#1860) (#1861) Disables 'misc-use-anonymous-namespace' for usage of the BENCHMARK macro. This warning is spurious, and the variable declared by the BENCHMARK macro can't be moved into an annonymous namespace. We don't want to disable it globally, but it can be disabled locally, for the `BENCHMARK` statement, as this warning appears downstream for users. See: https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics --- include/benchmark/benchmark.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 53a22247f2..86f9dbbabb 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1554,6 +1554,7 @@ class Fixture : public internal::Benchmark { BaseClass##_##Method##_Benchmark #define BENCHMARK_PRIVATE_DECLARE(n) \ + /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ static ::benchmark::internal::Benchmark* BENCHMARK_PRIVATE_NAME(n) \ BENCHMARK_UNUSED From 761305ec3b33abf30e08d50eb829e19a802581cc Mon Sep 17 00:00:00 2001 From: Alfredo Daniel Esponda Cervantes <92197886+aespondac@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:16:37 -0600 Subject: [PATCH 266/561] Update user_guide.md (#1863) PR for Issue #819: Fix Suffix in Console Format Table This PR fixes an issue with an incorrect suffix displayed in the console output. Fixes #819. --- docs/user_guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 64566f1f37..046d7dea87 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -82,9 +82,9 @@ tabular data on stdout. Example tabular output looks like: ``` Benchmark Time(ns) CPU(ns) Iterations ---------------------------------------------------------------------- -BM_SetInsert/1024/1 28928 29349 23853 133.097kB/s 33.2742k items/s -BM_SetInsert/1024/8 32065 32913 21375 949.487kB/s 237.372k items/s -BM_SetInsert/1024/10 33157 33648 21431 1.13369MB/s 290.225k items/s +BM_SetInsert/1024/1 28928 29349 23853 133.097kiB/s 33.2742k items/s +BM_SetInsert/1024/8 32065 32913 21375 949.487kiB/s 237.372k items/s +BM_SetInsert/1024/10 33157 33648 21431 1.13369MiB/s 290.225k items/s ``` The JSON format outputs human readable json split into two top level attributes. From 498714357f0a64f4f56523182cf75acd785f2d9d Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:27:18 +0100 Subject: [PATCH 267/561] upgrade bazel mods. requires c++14 for tests (#1867) --- MODULE.bazel | 8 ++++---- test/BUILD | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index e4f170c83d..4147925742 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -3,13 +3,13 @@ module( version = "1.9.0", ) -bazel_dep(name = "bazel_skylib", version = "1.5.0") -bazel_dep(name = "platforms", version = "0.0.8") +bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "rules_foreign_cc", version = "0.10.1") bazel_dep(name = "rules_cc", version = "0.0.9") -bazel_dep(name = "rules_python", version = "0.31.0", dev_dependency = True) -bazel_dep(name = "googletest", version = "1.12.1", dev_dependency = True, repo_name = "com_google_googletest") +bazel_dep(name = "rules_python", version = "0.37.0", dev_dependency = True) +bazel_dep(name = "googletest", version = "1.14.0", dev_dependency = True, repo_name = "com_google_googletest") bazel_dep(name = "libpfm", version = "4.11.0") diff --git a/test/BUILD b/test/BUILD index b245fa7622..f2179f61c1 100644 --- a/test/BUILD +++ b/test/BUILD @@ -10,7 +10,7 @@ platform( TEST_COPTS = [ "-pedantic", "-pedantic-errors", - "-std=c++11", + "-std=c++14", "-Wall", "-Wconversion", "-Wextra", From be2134584d6ee4f8c160c413d4df8e4c5db17d54 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Wed, 23 Oct 2024 11:38:53 +0200 Subject: [PATCH 268/561] Update nanobind_bazel to v2.2.0 (#1866) Adds support for free-threaded nanobind extension builds, though we don't currently build a free-threaded wheel. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 4147925742..40e306fafa 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -38,4 +38,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "2.1.0", dev_dependency = True) +bazel_dep(name = "nanobind_bazel", version = "2.2.0", dev_dependency = True) From c45d9c4c2fa077b7bb2018f1c52b0668b65d4b22 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:46:02 +0100 Subject: [PATCH 269/561] bump googletest version to match bazel (#1868) * bump googletest version to match bazel * bump minimum cmake to 3.13 per supported versions --- .github/workflows/build-and-test-min-cmake.yml | 2 +- CMakeLists.txt | 2 +- cmake/GoogleTest.cmake.in | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index b49800629b..2509984204 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -20,7 +20,7 @@ jobs: - uses: lukka/get-cmake@latest with: - cmakeVersion: 3.10.0 + cmakeVersion: 3.13.0 - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build diff --git a/CMakeLists.txt b/CMakeLists.txt index a86a5686ed..3aac35fe69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. -cmake_minimum_required (VERSION 3.10...3.22) +cmake_minimum_required (VERSION 3.13...3.22) project (benchmark VERSION 1.9.0 LANGUAGES CXX) diff --git a/cmake/GoogleTest.cmake.in b/cmake/GoogleTest.cmake.in index ce653ac375..c791446754 100644 --- a/cmake/GoogleTest.cmake.in +++ b/cmake/GoogleTest.cmake.in @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required (VERSION 3.13...3.22) project(googletest-download NONE) @@ -38,7 +38,7 @@ else() ExternalProject_Add( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG "release-1.11.0" + GIT_TAG "v1.14.0" PREFIX "${CMAKE_BINARY_DIR}" STAMP_DIR "${CMAKE_BINARY_DIR}/stamp" DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/download" From ffc727a859d9ae7631fbc7647392efa05032211a Mon Sep 17 00:00:00 2001 From: xdje42 Date: Thu, 24 Oct 2024 02:22:58 -0700 Subject: [PATCH 270/561] Verify RegisterProfilerManager doesn't overwrite an existing registration (#1837) * Verify RegisterProfilerManager doesn't overwrite an existing registration Tested: Add a second registration to test/profiler_manager_test.cc and verify the test crashes as expected. * Verify RegisterProfilerManager doesn't overwrite an existing registration Tested: Configure with: cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on Then run: ctest -R profiler_manager_gtest Before change test fails (expected), after change test passes (expected) --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/benchmark.cc | 4 ++++ test/CMakeLists.txt | 1 + test/profiler_manager_gtest.cc | 42 ++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 test/profiler_manager_gtest.cc diff --git a/src/benchmark.cc b/src/benchmark.cc index 2605077444..0ea90aeb6a 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -668,6 +668,10 @@ void RegisterMemoryManager(MemoryManager* manager) { } void RegisterProfilerManager(ProfilerManager* manager) { + // Don't allow overwriting an existing manager. + if (manager != nullptr) { + BM_CHECK_EQ(internal::profiler_manager, nullptr); + } internal::profiler_manager = manager; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 815b581889..321e24d94b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -254,6 +254,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS) add_gtest(perf_counters_gtest) add_gtest(time_unit_gtest) add_gtest(min_time_parse_gtest) + add_gtest(profiler_manager_gtest) endif(BENCHMARK_ENABLE_GTEST_TESTS) ############################################################################### diff --git a/test/profiler_manager_gtest.cc b/test/profiler_manager_gtest.cc new file mode 100644 index 0000000000..434e4ecadf --- /dev/null +++ b/test/profiler_manager_gtest.cc @@ -0,0 +1,42 @@ +#include + +#include "benchmark/benchmark.h" +#include "gtest/gtest.h" + +namespace { + +class TestProfilerManager : public benchmark::ProfilerManager { + public: + void AfterSetupStart() override { ++start_called; } + void BeforeTeardownStop() override { ++stop_called; } + + int start_called = 0; + int stop_called = 0; +}; + +void BM_empty(benchmark::State& state) { + for (auto _ : state) { + auto iterations = state.iterations(); + benchmark::DoNotOptimize(iterations); + } +} +BENCHMARK(BM_empty); + +TEST(ProfilerManager, ReregisterManager) { +#if GTEST_HAS_DEATH_TEST + // Tests only runnable in debug mode (when BM_CHECK is enabled). +#ifndef NDEBUG +#ifndef TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS + ASSERT_DEATH_IF_SUPPORTED( + { + std::unique_ptr pm(new TestProfilerManager()); + benchmark::RegisterProfilerManager(pm.get()); + benchmark::RegisterProfilerManager(pm.get()); + }, + "RegisterProfilerManager"); +#endif +#endif +#endif +} + +} // namespace From 4e3f2d8b6728d628b3baa77a8d2359dd8e35bab5 Mon Sep 17 00:00:00 2001 From: Richard Cole Date: Thu, 24 Oct 2024 12:31:06 +0100 Subject: [PATCH 271/561] [#1487] ensure that when printing color text the background color of the terminal on windows is preserved (#1865) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/colorprint.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/colorprint.cc b/src/colorprint.cc index abc71492f7..fd1971ad3c 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -135,19 +135,25 @@ void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); - const WORD old_color_attrs = buffer_info.wAttributes; + const WORD original_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. out.flush(); - SetConsoleTextAttribute(stdout_handle, - GetPlatformColorCode(color) | FOREGROUND_INTENSITY); + + const WORD original_background_attrs = + original_color_attrs & (BACKGROUND_RED | BACKGROUND_GREEN | + BACKGROUND_BLUE | BACKGROUND_INTENSITY); + + SetConsoleTextAttribute(stdout_handle, GetPlatformColorCode(color) | + FOREGROUND_INTENSITY | + original_background_attrs); out << FormatString(fmt, args); out.flush(); - // Restores the text color. - SetConsoleTextAttribute(stdout_handle, old_color_attrs); + // Restores the text and background color. + SetConsoleTextAttribute(stdout_handle, original_color_attrs); #else const char* color_code = GetPlatformColorCode(color); if (color_code) out << FormatString("\033[0;3%sm", color_code); From d99cdd7356de97b3056684d6b511189778d8a247 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 28 Oct 2024 19:18:40 +0100 Subject: [PATCH 272/561] Add `nb::is_flag()` annotation to Counter::Flags (#1870) This saves us the definition of `__or__`, because we can just use the one from `enum.IntFlag`. --- bindings/python/google_benchmark/benchmark.cc | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index 64ffb92b48..a935822536 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -118,7 +118,7 @@ NB_MODULE(_benchmark, m) { using benchmark::Counter; nb::class_ py_counter(m, "Counter"); - nb::enum_(py_counter, "Flags", nb::is_arithmetic()) + nb::enum_(py_counter, "Flags", nb::is_arithmetic(), nb::is_flag()) .value("kDefaults", Counter::Flags::kDefaults) .value("kIsRate", Counter::Flags::kIsRate) .value("kAvgThreads", Counter::Flags::kAvgThreads) @@ -129,10 +129,7 @@ NB_MODULE(_benchmark, m) { .value("kAvgIterations", Counter::Flags::kAvgIterations) .value("kAvgIterationsRate", Counter::Flags::kAvgIterationsRate) .value("kInvert", Counter::Flags::kInvert) - .export_values() - .def("__or__", [](Counter::Flags a, Counter::Flags b) { - return static_cast(a) | static_cast(b); - }); + .export_values(); nb::enum_(py_counter, "OneK") .value("kIs1000", Counter::OneK::kIs1000) @@ -140,13 +137,9 @@ NB_MODULE(_benchmark, m) { .export_values(); py_counter - .def( - "__init__", - [](Counter* c, double value, int flags, Counter::OneK oneK) { - new (c) Counter(value, static_cast(flags), oneK); - }, - nb::arg("value") = 0., nb::arg("flags") = Counter::kDefaults, - nb::arg("k") = Counter::kIs1000) + .def(nb::init(), + nb::arg("value") = 0., nb::arg("flags") = Counter::kDefaults, + nb::arg("k") = Counter::kIs1000) .def("__init__", ([](Counter* c, double value) { new (c) Counter(value); })) .def_rw("value", &Counter::value) From a6af6eeb6a53c599365bc405539c1ec044fefb32 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Wed, 6 Nov 2024 14:15:22 +0100 Subject: [PATCH 273/561] Add a Python matrix to ensure the bindings build on all supported versions (#1871) Also contains a run of `pre-commit autoupdate`, and a bump of cibuildwheel to its latest tag for CPython 3.13 support. But, since we build for 3.10+ with SABI from 3.12 onwards, we don't even need a dedicated Python 3.13 build job or toolchain - the wheels from 3.12 can be reused. Simplifies some version-dependent logic around assembling the bazel build command in setup.py, and fixes a possible unbound local error in the toolchain patch context manager. --- .github/workflows/test_bindings.yml | 12 ++++++------ .github/workflows/wheels.yml | 2 +- .pre-commit-config.yaml | 6 +++--- setup.py | 22 ++++++++++++++-------- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 436a8f90e5..b6ac9be8cb 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -8,23 +8,23 @@ on: jobs: python_bindings: - name: Test GBM Python bindings on ${{ matrix.os }} + name: Test GBM Python ${{ matrix.python-version }} bindings on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] + python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Set up Python 3.11 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: ${{ matrix.python-version }} - name: Install GBM Python bindings on ${{ matrix.os }} run: python -m pip install . - - name: Run bindings example on ${{ matrix.os }} - run: - python bindings/python/google_benchmark/example.py + - name: Run example on ${{ matrix.os }} under Python ${{ matrix.python-version }} + run: python bindings/python/google_benchmark/example.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 7544b24758..b463ff83dd 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -53,7 +53,7 @@ jobs: platforms: all - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.20 + uses: pypa/cibuildwheel@v2.21.3 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ef13c1dabd..2a51592edf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 7.1.2 + rev: 7.3.1 hooks: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.1 + rev: v1.13.0 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.1 + rev: v0.7.2 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/setup.py b/setup.py index 1e4c0db761..238d9d8987 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ import platform import re import shutil +import sys from pathlib import Path from typing import Any, Generator @@ -15,8 +16,7 @@ # hardcoded SABI-related options. Requires that each Python interpreter # (hermetic or not) participating is of the same major-minor version. -version_tuple = tuple(int(i) for i in platform.python_version_tuple()) -py_limited_api = version_tuple >= (3, 12) +py_limited_api = sys.version_info >= (3, 12) options = {"bdist_wheel": {"py_limited_api": "cp312"}} if py_limited_api else {} @@ -43,10 +43,10 @@ def fmt_toolchain_args(matchobj): return "python.toolchain(" + callargs + ")" CIBW_LINUX = is_cibuildwheel() and IS_LINUX + module_bazel = Path("MODULE.bazel") + content: str = module_bazel.read_text() try: if CIBW_LINUX: - module_bazel = Path("MODULE.bazel") - content: str = module_bazel.read_text() module_bazel.write_text( re.sub( r"python.toolchain\(([\w\"\s,.=]*)\)", @@ -92,10 +92,16 @@ def copy_extensions_to_source(self): def bazel_build(self, ext: BazelExtension) -> None: """Runs the bazel build to create the package.""" temp_path = Path(self.build_temp) - # omit the patch version to avoid build errors if the toolchain is not - # yet registered in the current @rules_python version. - # patch version differences should be fine. - python_version = ".".join(platform.python_version_tuple()[:2]) + if py_limited_api: + # We only need to know the minimum ABI version, + # since it is stable across minor versions by definition. + # The value here is calculated as the minimum of a) the minimum + # Python version required, and b) the stable ABI version target. + # NB: This needs to be kept in sync with [project.requires-python] + # in pyproject.toml. + python_version = "3.12" + else: + python_version = "{0}.{1}".format(*sys.version_info[:2]) bazel_argv = [ "bazel", From 50ffd3e546c51686e468042721704ad59d4e0eac Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Thu, 7 Nov 2024 16:04:51 +0100 Subject: [PATCH 274/561] Declare a Python 3.13 toolchain, revert setup.py toolchain arget selection (#1876) The new solution was too smart (read: dense), because it did not account for the fact that we look for the Windows libs of the interpreter building the wheel, not the hermetic one supplying the header files. The fix is to just align the versions again, so that the libs and headers come from the same minor version. --- MODULE.bazel | 1 + setup.py | 14 ++++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 40e306fafa..092ee18068 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -27,6 +27,7 @@ python.toolchain( is_default = True, python_version = "3.12", ) +python.toolchain(python_version = "3.13") pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) pip.parse( diff --git a/setup.py b/setup.py index 238d9d8987..69cc49da7a 100644 --- a/setup.py +++ b/setup.py @@ -92,16 +92,10 @@ def copy_extensions_to_source(self): def bazel_build(self, ext: BazelExtension) -> None: """Runs the bazel build to create the package.""" temp_path = Path(self.build_temp) - if py_limited_api: - # We only need to know the minimum ABI version, - # since it is stable across minor versions by definition. - # The value here is calculated as the minimum of a) the minimum - # Python version required, and b) the stable ABI version target. - # NB: This needs to be kept in sync with [project.requires-python] - # in pyproject.toml. - python_version = "3.12" - else: - python_version = "{0}.{1}".format(*sys.version_info[:2]) + + # We round to the minor version, which makes rules_python + # look up the latest available patch version internally. + python_version = "{0}.{1}".format(*sys.version_info[:2]) bazel_argv = [ "bazel", From 62a321d6dc377e0ba9c712b6a8d64360616de564 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:06:48 +0000 Subject: [PATCH 275/561] update standard to C++17 per C++ build support (#1875) * update standard to C++17 per C++ build support * disable deadcode checks from clang-tidy * fix redundant definition of constexpr --- .github/workflows/clang-tidy.yml | 2 +- BUILD.bazel | 2 +- CMakeLists.txt | 2 +- src/perf_counters.cc | 2 -- test/BUILD | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 558375e3ae..37a61cdb3a 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -35,4 +35,4 @@ jobs: - name: run shell: bash working-directory: ${{ runner.workspace }}/_build - run: run-clang-tidy + run: run-clang-tidy -checks=*,-clang-analyzer-deadcode* diff --git a/BUILD.bazel b/BUILD.bazel index 094ed62437..3451b4e758 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3,7 +3,7 @@ licenses(["notice"]) COPTS = [ "-pedantic", "-pedantic-errors", - "-std=c++14", + "-std=c++17", "-Wall", "-Wconversion", "-Wextra", diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aac35fe69..c90529d8b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,7 +138,7 @@ if (BENCHMARK_BUILD_32_BITS) add_required_cxx_compiler_flag(-m32) endif() -set(BENCHMARK_CXX_STANDARD 14) +set(BENCHMARK_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD ${BENCHMARK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED YES) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index fc9586b716..a2fa7fe35f 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -26,8 +26,6 @@ namespace benchmark { namespace internal { -constexpr size_t PerfCounterValues::kMaxCounters; - #if defined HAVE_LIBPFM size_t PerfCounterValues::Read(const std::vector& leaders) { diff --git a/test/BUILD b/test/BUILD index f2179f61c1..c1ca86b5b2 100644 --- a/test/BUILD +++ b/test/BUILD @@ -10,7 +10,7 @@ platform( TEST_COPTS = [ "-pedantic", "-pedantic-errors", - "-std=c++14", + "-std=c++17", "-Wall", "-Wconversion", "-Wextra", From d26047a0ac8485721f3bf1dfe21374cddb58ea3b Mon Sep 17 00:00:00 2001 From: Guo Ci Date: Wed, 27 Nov 2024 04:41:06 -0500 Subject: [PATCH 276/561] Improve examples on `ComputeStatistics` (#1881) --- docs/user_guide.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 046d7dea87..315276277b 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1106,6 +1106,7 @@ void BM_spin_empty(benchmark::State& state) { } BENCHMARK(BM_spin_empty) + ->Repetitions(3) // or add option --benchmark_repetitions=3 ->ComputeStatistics("max", [](const std::vector& v) -> double { return *(std::max_element(std::begin(v), std::end(v))); }) @@ -1125,8 +1126,9 @@ void BM_spin_empty(benchmark::State& state) { } BENCHMARK(BM_spin_empty) + ->Repetitions(3) // or add option --benchmark_repetitions=3 ->ComputeStatistics("ratio", [](const std::vector& v) -> double { - return std::begin(v) / std::end(v); + return v.front() / v.back(); }, benchmark::StatisticUnit::kPercentage) ->Arg(512); ``` From c58e6d0710581e3a08d65c349664128a8d9a2461 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 28 Nov 2024 16:51:38 +0000 Subject: [PATCH 277/561] v1.9.1 bump --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c90529d8b3..f045fcd848 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.13...3.22) -project (benchmark VERSION 1.9.0 LANGUAGES CXX) +project (benchmark VERSION 1.9.1 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 092ee18068..62870f74f7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.9.0", + version = "1.9.1", ) bazel_dep(name = "bazel_skylib", version = "1.7.1") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index e7870c854c..7006352669 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -50,7 +50,7 @@ def my_benchmark(state): oNSquared as oNSquared, ) -__version__ = "1.9.0" +__version__ = "1.9.1" class __OptionMaker: From 4b0533b726dd8613f7d5fd0d1d044ce81f05651d Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Fri, 29 Nov 2024 12:06:08 +0100 Subject: [PATCH 278/561] Add artifact name to download before wheel PyPI upload (#1882) Otherwise, the folder structure gets messed up, and twine errors out. --- .github/workflows/wheels.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b463ff83dd..e2a96bd067 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -77,7 +77,7 @@ jobs: merge_wheels: name: Merge all built wheels into one artifact runs-on: ubuntu-latest - needs: build_wheels + needs: [build_sdist, build_wheels] steps: - name: Merge wheels uses: actions/upload-artifact/merge@v4 @@ -96,5 +96,6 @@ jobs: steps: - uses: actions/download-artifact@v4 with: + name: dist path: dist - uses: pypa/gh-action-pypi-publish@release/v1 From 3d88affa59e15018831cc36229c43ab9e741a667 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Fri, 29 Nov 2024 12:55:32 +0100 Subject: [PATCH 279/561] Remove if statement from wheel upload job (#1883) This to see if it works with the new artifact download config. --- .github/workflows/wheels.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e2a96bd067..74676be830 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -90,7 +90,6 @@ jobs: name: Publish google-benchmark wheels to PyPI needs: [merge_wheels] runs-on: ubuntu-latest - if: github.event_name == 'release' && github.event.action == 'published' permissions: id-token: write steps: From b2b0aab464b1d5be3cf1728d36bb03f8b84f246f Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 3 Dec 2024 18:42:57 +0100 Subject: [PATCH 280/561] Fix malformed clang invocation in build_ext.run (#1884) The fix is, unsurprisingly, to not invoke clang at all, because we use Bazel to build everything anyway. This also means that we can drop the setuptools pin. --- pyproject.toml | 2 +- setup.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 14f173f956..338b0b907d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools<73"] +requires = ["setuptools"] build-backend = "setuptools.build_meta" [project] diff --git a/setup.py b/setup.py index 69cc49da7a..5393350824 100644 --- a/setup.py +++ b/setup.py @@ -77,7 +77,6 @@ class BuildBazelExtension(build_ext.build_ext): def run(self): for ext in self.extensions: self.bazel_build(ext) - super().run() # explicitly call `bazel shutdown` for graceful exit self.spawn(["bazel", "shutdown"]) From b32ae9c9afd800a010bac61a1e4a44aff24094e1 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 10 Dec 2024 12:04:53 +0000 Subject: [PATCH 281/561] remove noenable_bzlmod as workspace support is going away --- .github/workflows/bazel.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index b50a8f6464..f86b1a06d7 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -6,7 +6,7 @@ on: jobs: build_and_test_default: - name: bazel.${{ matrix.os }}.${{ matrix.bzlmod && 'bzlmod' || 'no_bzlmod' }} + name: bazel.${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -28,8 +28,8 @@ jobs: - name: build run: | - bazel build ${{ matrix.bzlmod && '--enable_bzlmod' || '--noenable_bzlmod' }} //:benchmark //:benchmark_main //test/... + bazel build //:benchmark //:benchmark_main //test/... - name: test run: | - bazel test ${{ matrix.bzlmod && '--enable_bzlmod' || '--noenable_bzlmod' }} --test_output=all //test/... + bazel test --test_output=all //test/... From c8c66e0b4a4c37558ce40ab4ca45f9d3f86a97d3 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 10 Dec 2024 12:07:53 +0000 Subject: [PATCH 282/561] remove unnecessary bazel action parameter --- .github/workflows/bazel.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index f86b1a06d7..ea231a3c4d 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -12,7 +12,6 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - bzlmod: [false, true] steps: - uses: actions/checkout@v4 From ae52c9e66e776d401636aa9e26b3a1b50746f3ab Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 10 Dec 2024 13:27:12 +0100 Subject: [PATCH 283/561] Remove wheel merge job, merge artifacts on download (#1886) This is supported by `actions/download-artifact@v4`, and endorsed by cibuildwheel in their documentation (see https://cibuildwheel.pypa.io/en/stable/deliver-to-pypi/#github-actions). Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 74676be830..0569dcc90f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -53,12 +53,11 @@ jobs: platforms: all - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.21.3 + uses: pypa/cibuildwheel@v2.22.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" CIBW_SKIP: "*-musllinux_*" - CIBW_TEST_SKIP: "cp38-macosx_*:arm64" CIBW_ARCHS_LINUX: auto64 aarch64 CIBW_ARCHS_WINDOWS: auto64 CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh @@ -74,27 +73,16 @@ jobs: name: dist-${{ matrix.os }} path: wheelhouse/*.whl - merge_wheels: - name: Merge all built wheels into one artifact - runs-on: ubuntu-latest - needs: [build_sdist, build_wheels] - steps: - - name: Merge wheels - uses: actions/upload-artifact/merge@v4 - with: - name: dist - pattern: dist-* - delete-merged: true - pypi_upload: name: Publish google-benchmark wheels to PyPI - needs: [merge_wheels] + needs: [build_sdist, build_wheels] runs-on: ubuntu-latest permissions: id-token: write steps: - uses: actions/download-artifact@v4 with: - name: dist path: dist + pattern: dist-* + merge-multiple: true - uses: pypa/gh-action-pypi-publish@release/v1 From f4f93b5553ced834b2120048f65690cddb4b7a2f Mon Sep 17 00:00:00 2001 From: Devon Loehr Date: Tue, 10 Dec 2024 10:29:03 -0500 Subject: [PATCH 284/561] Change SDK version check (#1887) Now that github seems to have updated its builders, perhaps we can check the SDK version the more standard way. --- src/sysinfo.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 7148598264..49bff75e58 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -354,8 +354,7 @@ std::vector GetCacheSizesWindows() { C.type = "Unknown"; switch (cache.Type) { // Windows SDK version >= 10.0.26100.0 -// 0x0A000010 is the value of NTDDI_WIN11_GE -#if NTDDI_VERSION >= 0x0A000010 +#ifdef NTDDI_WIN11_GE case CacheUnknown: break; #endif From 5af40e824defae36fb70521c793af0594599ac7e Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 8 Jan 2025 03:26:44 -0800 Subject: [PATCH 285/561] [bazel] Remove selects on CPU (#1892) In a future version of bazel this produces a warning. In this case using only the platform being windows is enough. Fixes: ``` WARNING: /.../benchmark/BUILD.bazel:29:15: in config_setting rule //:windows: select() on cpu is deprecated. Use platform constraints instead: https://bazel.build/docs/configurable-attributes#platforms. ``` --- BUILD.bazel | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 3451b4e758..95557a35b2 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -17,30 +17,12 @@ COPTS = [ "-Werror=old-style-cast", ] -config_setting( - name = "qnx", - constraint_values = ["@platforms//os:qnx"], - values = { - "cpu": "x64_qnx", - }, - visibility = [":__subpackages__"], -) - config_setting( name = "windows", constraint_values = ["@platforms//os:windows"], - values = { - "cpu": "x64_windows", - }, visibility = [":__subpackages__"], ) -config_setting( - name = "macos", - constraint_values = ["@platforms//os:macos"], - visibility = ["//visibility:public"], -) - config_setting( name = "perfcounters", define_values = { From f65741b2bd92461dc2c816056eb9c996ae48ad62 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 8 Jan 2025 13:03:53 +0100 Subject: [PATCH 286/561] cycleclock: Support for PA-RISC (hppa) architecture (#1894) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/cycleclock.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cycleclock.h b/src/cycleclock.h index bd62f5d7e7..7852f3df52 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -229,6 +229,16 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { struct timeval tv; gettimeofday(&tv, nullptr); return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#elif defined(__hppa__) + // HP PA-RISC provides a user-readable clock counter (cr16), but + // it's not syncronized across CPUs and only 32-bit wide when programs + // are built as 32-bit binaries. + // Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday + // because is provides nanosecond resolution. + // Initialize to always return 0 if clock_gettime fails. + struct timespec ts = {0, 0}; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) * 1000000000 + ts.tv_nsec; #else // The soft failover to a generic implementation is automatic only for ARM. // For other platforms the developer is expected to make an attempt to create From 7ddc400d6232259e9acc6e09cd77c9a6f758e030 Mon Sep 17 00:00:00 2001 From: Hamza Date: Wed, 8 Jan 2025 12:41:17 +0000 Subject: [PATCH 287/561] fix: remove clang-cl compilation warning (#1895) - MP flag only applies to cl, not cl frontends to other compilers (e.g. clang-cl, icx-cl etc). Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f045fcd848..fd6906040d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,7 +147,12 @@ set(CMAKE_CXX_EXTENSIONS OFF) if (MSVC) # Turn compiler warnings up to 11 string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") + + # MP flag only applies to cl, not cl frontends to other compilers (e.g. clang-cl, icx-cl etc) + if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + endif() add_definitions(-D_CRT_SECURE_NO_WARNINGS) if(BENCHMARK_ENABLE_WERROR) From f981f58da37d1e7214f8b498d5055e48361380b9 Mon Sep 17 00:00:00 2001 From: 0dminnimda <0dminnimda@gmail.com> Date: Wed, 8 Jan 2025 15:49:09 +0300 Subject: [PATCH 288/561] README.md: fix build instructions (#1880) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e5428f995..c77f9b6cbe 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ $ cmake -E make_directory "build" # Generate build system files with cmake, and download any dependencies. $ cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release ../ # or, starting with CMake 3.13, use a simpler form: -# cmake -DCMAKE_BUILD_TYPE=Release -S . -B "build" +# cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release -S . -B "build" # Build the library. $ cmake --build "build" --config Release ``` From 077db43001b42af3ad23e993b2bdcb4fadb7bcf8 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 8 Jan 2025 17:54:08 +0100 Subject: [PATCH 289/561] cycleclock: Use cock_gettime() as fallback for any Linux architecture (#1899) The Linux kernel provides the clock_gettime() functions since a long time already, so it's possible to use it as a generic fallback option for any architecture if no other (better) possibility has been provided instead. I noticed the benchmark package failed to build on debian on the SH-4 architecture, so with this change SH-4 is now the first user of this fallback option. --- src/cycleclock.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index 7852f3df52..03e02f8055 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -229,10 +229,12 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { struct timeval tv; gettimeofday(&tv, nullptr); return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; -#elif defined(__hppa__) +#elif defined(__hppa__) || defined(__linux__) + // Fallback for all other architectures with a recent Linux kernel, e.g.: // HP PA-RISC provides a user-readable clock counter (cr16), but // it's not syncronized across CPUs and only 32-bit wide when programs // are built as 32-bit binaries. + // Same for SH-4 and possibly others. // Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday // because is provides nanosecond resolution. // Initialize to always return 0 if clock_gettime fails. From 39be87d3004ff9ff4cdf736651af80c3d15e2497 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 9 Jan 2025 11:47:29 +0100 Subject: [PATCH 290/561] Fix runtime crash when parsing /proc/cpuinfo fails (#1900) The testcase fails on sparc64, because the parsing of /proc/cpuinfo fails and thus currently returns "0" CPUs which finally leads to division-by-zero faults in the tests. Fix the issue by returning at least "1" CPU which allows the tests to run. A error message will be printed in any case. Long-term the code should be fixed to parse the cpuinfo output on sparch which looks like this: ... type : sun4v ncpus probed : 48 ncpus active : 48 --- src/sysinfo.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 49bff75e58..ce14b8d8ed 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -561,10 +561,12 @@ int GetNumCPUsImpl() { } int GetNumCPUs() { - const int num_cpus = GetNumCPUsImpl(); + int num_cpus = GetNumCPUsImpl(); if (num_cpus < 1) { std::cerr << "Unable to extract number of CPUs. If your platform uses " "/proc/cpuinfo, custom support may need to be added.\n"; + /* There is at least one CPU which we run on. */ + num_cpus = 1; } return num_cpus; } From c24774dc4f4402c3ad150363321cc972ed2669e7 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 9 Jan 2025 17:07:43 +0100 Subject: [PATCH 291/561] Get number of CPUs with sysconf() on Linux (#1901) * Get number of CPUs with sysconf() on Linux Avoid parsing the /proc/cpuinfo just to get number of CPUs. Instead use the portable function provided by glibc. * Update sysinfo.cc --- src/sysinfo.cc | 54 +++----------------------------------------------- 1 file changed, 3 insertions(+), 51 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index ce14b8d8ed..eddd430e68 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -492,14 +492,14 @@ int GetNumCPUsImpl() { GetSystemInfo(&sysinfo); // number of logical processors in the current group return static_cast(sysinfo.dwNumberOfProcessors); -#elif defined(BENCHMARK_OS_SOLARIS) +#elif defined(__linux__) || defined(BENCHMARK_OS_SOLARIS) // Returns -1 in case of a failure. - long num_cpu = sysconf(_SC_NPROCESSORS_ONLN); + int num_cpu = static_cast(sysconf(_SC_NPROCESSORS_ONLN)); if (num_cpu < 0) { PrintErrorAndDie("sysconf(_SC_NPROCESSORS_ONLN) failed with error: ", strerror(errno)); } - return (int)num_cpu; + return num_cpu; #elif defined(BENCHMARK_OS_QNX) return static_cast(_syspage_ptr->num_cpu); #elif defined(BENCHMARK_OS_QURT) @@ -508,54 +508,6 @@ int GetNumCPUsImpl() { hardware_threads.max_hthreads = 1; } return hardware_threads.max_hthreads; -#else - int num_cpus = 0; - int max_id = -1; - std::ifstream f("/proc/cpuinfo"); - if (!f.is_open()) { - std::cerr << "Failed to open /proc/cpuinfo\n"; - return -1; - } -#if defined(__alpha__) - const std::string Key = "cpus detected"; -#else - const std::string Key = "processor"; -#endif - std::string ln; - while (std::getline(f, ln)) { - if (ln.empty()) continue; - std::size_t split_idx = ln.find(':'); - std::string value; -#if defined(__s390__) - // s390 has another format in /proc/cpuinfo - // it needs to be parsed differently - if (split_idx != std::string::npos) - value = ln.substr(Key.size() + 1, split_idx - Key.size() - 1); -#else - if (split_idx != std::string::npos) value = ln.substr(split_idx + 1); -#endif - if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) { - num_cpus++; - if (!value.empty()) { - const int cur_id = benchmark::stoi(value); - max_id = std::max(cur_id, max_id); - } - } - } - if (f.bad()) { - PrintErrorAndDie("Failure reading /proc/cpuinfo"); - } - if (!f.eof()) { - PrintErrorAndDie("Failed to read to end of /proc/cpuinfo"); - } - f.close(); - - if ((max_id + 1) != num_cpus) { - fprintf(stderr, - "CPU ID assignments in /proc/cpuinfo seem messed up." - " This is usually caused by a bad BIOS.\n"); - } - return num_cpus; #endif BENCHMARK_UNREACHABLE(); } From 4834ae9e57589cde4c8fbbdbdcb680d54c0a38e1 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 13 Jan 2025 14:33:04 +0100 Subject: [PATCH 292/561] Update nanobind-bazel to v2.4.0 (#1904) Contains nanobind v2.4.0, which brings some more functionality, free-threading fixes, and performance improvements. --- MODULE.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 62870f74f7..62a3aa8ba4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,7 +8,7 @@ bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "rules_foreign_cc", version = "0.10.1") bazel_dep(name = "rules_cc", version = "0.0.9") -bazel_dep(name = "rules_python", version = "0.37.0", dev_dependency = True) +bazel_dep(name = "rules_python", version = "1.0.0", dev_dependency = True) bazel_dep(name = "googletest", version = "1.14.0", dev_dependency = True, repo_name = "com_google_googletest") bazel_dep(name = "libpfm", version = "4.11.0") @@ -39,4 +39,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "2.2.0", dev_dependency = True) +bazel_dep(name = "nanobind_bazel", version = "2.4.0", dev_dependency = True) From d6536acfe80d05d2b9e63e4dc786dd1dc9f0b960 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 13 Jan 2025 14:38:59 +0100 Subject: [PATCH 293/561] ci: Update pre-commit hooks (#1905) As a fix, also turn the comment in libpfm's build file into a proper Starlark docstring. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- tools/libpfm.BUILD.bazel | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2a51592edf..78a4580763 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 7.3.1 + rev: 8.0.0 hooks: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.13.0 + rev: v1.14.1 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.2 + rev: v0.9.1 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/tools/libpfm.BUILD.bazel b/tools/libpfm.BUILD.bazel index 62695342aa..4ef112352f 100644 --- a/tools/libpfm.BUILD.bazel +++ b/tools/libpfm.BUILD.bazel @@ -1,5 +1,4 @@ -# Build rule for libpfm, which is required to collect performance counters for -# BENCHMARK_ENABLE_LIBPFM builds. +"""Build rule for libpfm, which is required to collect performance counters for BENCHMARK_ENABLE_LIBPFM builds.""" load("@rules_foreign_cc//foreign_cc:defs.bzl", "make") From ecb5df647341456596928d72c4c56b3f438a005e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 22 Jan 2025 12:50:00 +0100 Subject: [PATCH 294/561] Lint Python: Add more ruff rules (#1909) * Lint Python: Add more ruff rules * range(len()) --> enumerate() * zip(strict=True) --- .pre-commit-config.yaml | 2 +- bindings/python/google_benchmark/example.py | 3 +- pyproject.toml | 6 +- setup.py | 14 ++- tools/compare.py | 4 +- tools/gbench/report.py | 106 +++++++++++--------- tools/gbench/util.py | 46 ++++----- tools/strip_asm.py | 14 +-- 8 files changed, 98 insertions(+), 97 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 78a4580763..c16928a946 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.1 + rev: v0.9.2 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/bindings/python/google_benchmark/example.py b/bindings/python/google_benchmark/example.py index b92245ea67..5909c0fc0e 100644 --- a/bindings/python/google_benchmark/example.py +++ b/bindings/python/google_benchmark/example.py @@ -57,7 +57,7 @@ def skipped(state): state.skip_with_error("some error") return # NOTE: You must explicitly return, or benchmark will continue. - ... # Benchmark code would be here. + # Benchmark code would be here. @benchmark.register @@ -78,7 +78,6 @@ def custom_counters(state): num_foo = 0.0 while state: # Benchmark some code here - pass # Collect some custom metric named foo num_foo += 0.13 diff --git a/pyproject.toml b/pyproject.toml index 338b0b907d..761473c204 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,9 +68,11 @@ target-version = "py311" [tool.ruff.lint] # Enable pycodestyle (`E`, `W`), Pyflakes (`F`), and isort (`I`) codes by default. -select = ["E", "F", "I", "W"] +select = ["ASYNC", "B", "C4", "C90", "E", "F", "I", "PERF", "PIE", "PT018", "RUF", "SIM", "UP", "W"] ignore = [ - "E501", # line too long + "E501", # line too long + "PLW2901", # redefined-loop-name + "UP031", # printf-string-formatting ] [tool.ruff.lint.isort] diff --git a/setup.py b/setup.py index 5393350824..3c0269b199 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,9 @@ import re import shutil import sys +from collections.abc import Generator from pathlib import Path -from typing import Any, Generator +from typing import Any import setuptools from setuptools.command import build_ext @@ -86,15 +87,14 @@ def copy_extensions_to_source(self): This is done in the ``bazel_build`` method, so it's not necessary to do again in the `build_ext` base class. """ - pass - def bazel_build(self, ext: BazelExtension) -> None: + def bazel_build(self, ext: BazelExtension) -> None: # noqa: C901 """Runs the bazel build to create the package.""" temp_path = Path(self.build_temp) # We round to the minor version, which makes rules_python # look up the latest available patch version internally. - python_version = "{0}.{1}".format(*sys.version_info[:2]) + python_version = "{}.{}".format(*sys.version_info[:2]) bazel_argv = [ "bazel", @@ -142,9 +142,7 @@ def bazel_build(self, ext: BazelExtension) -> None: # we do not want the bare .so file included # when building for ABI3, so we require a # full and exact match on the file extension. - if "".join(fp.suffixes) == suffix: - should_copy = True - elif fp.suffix == ".pyi": + if "".join(fp.suffixes) == suffix or fp.suffix == ".pyi": should_copy = True elif Path(root) == srcdir and f == "py.typed": # copy py.typed, but only at the package root. @@ -155,7 +153,7 @@ def bazel_build(self, ext: BazelExtension) -> None: setuptools.setup( - cmdclass=dict(build_ext=BuildBazelExtension), + cmdclass={"build_ext": BuildBazelExtension}, package_data={"google_benchmark": ["py.typed", "*.pyi"]}, ext_modules=[ BazelExtension( diff --git a/tools/compare.py b/tools/compare.py index 7572520cc0..36cbe07569 100755 --- a/tools/compare.py +++ b/tools/compare.py @@ -94,9 +94,7 @@ def create_parser(): dest="utest", default=True, action="store_false", - help="The tool can do a two-tailed Mann-Whitney U test with the null hypothesis that it is equally likely that a randomly selected value from one sample will be less than or greater than a randomly selected value from a second sample.\nWARNING: requires **LARGE** (no less than {}) number of repetitions to be meaningful!\nThe test is being done by default, if at least {} repetitions were done.\nThis option can disable the U Test.".format( - report.UTEST_OPTIMAL_REPETITIONS, report.UTEST_MIN_REPETITIONS - ), + help=f"The tool can do a two-tailed Mann-Whitney U test with the null hypothesis that it is equally likely that a randomly selected value from one sample will be less than or greater than a randomly selected value from a second sample.\nWARNING: requires **LARGE** (no less than {report.UTEST_OPTIMAL_REPETITIONS}) number of repetitions to be meaningful!\nThe test is being done by default, if at least {report.UTEST_MIN_REPETITIONS} repetitions were done.\nThis option can disable the U Test.", ) alpha_default = 0.05 utest.add_argument( diff --git a/tools/gbench/report.py b/tools/gbench/report.py index 7158fd1654..6b58918bfc 100644 --- a/tools/gbench/report.py +++ b/tools/gbench/report.py @@ -14,7 +14,7 @@ from scipy.stats import gmean, mannwhitneyu -class BenchmarkColor(object): +class BenchmarkColor: def __init__(self, name, code): self.name = name self.code = code @@ -249,9 +249,7 @@ def get_utest_color(pval): # We still got some results to show but issue a warning about it. if not utest["have_optimal_repetitions"]: dsc_color = BC_WARNING - dsc += ". WARNING: Results unreliable! {}+ repetitions recommended.".format( - UTEST_OPTIMAL_REPETITIONS - ) + dsc += f". WARNING: Results unreliable! {UTEST_OPTIMAL_REPETITIONS}+ repetitions recommended." special_str = "{}{:<{}s}{endc}{}{:16.4f}{endc}{}{:16.4f}{endc}{} {}" @@ -260,7 +258,7 @@ def get_utest_color(pval): use_color, special_str, BC_HEADER, - "{}{}".format(bc_name, UTEST_COL_NAME), + f"{bc_name}{UTEST_COL_NAME}", first_col_width, get_utest_color(utest["time_pvalue"]), utest["time_pvalue"], @@ -285,7 +283,7 @@ def get_difference_report(json1, json2, utest=False): partitions = partition_benchmarks(json1, json2) for partition in partitions: benchmark_name = partition[0][0]["name"] - label = partition[0][0]["label"] if "label" in partition[0][0] else "" + label = partition[0][0].get("label", "") time_unit = partition[0][0]["time_unit"] measurements = [] utest_results = {} @@ -329,11 +327,7 @@ def get_difference_report(json1, json2, utest=False): # time units which are not compatible with other time units in the # benchmark suite. if measurements: - run_type = ( - partition[0][0]["run_type"] - if "run_type" in partition[0][0] - else "" - ) + run_type = partition[0][0].get("run_type", "") aggregate_name = ( partition[0][0]["aggregate_name"] if run_type == "aggregate" @@ -464,7 +458,7 @@ def load_results(self): os.path.dirname(os.path.realpath(__file__)), "Inputs" ) testOutput = os.path.join(testInputs, "test3_run0.json") - with open(testOutput, "r") as f: + with open(testOutput) as f: json = json.load(f) return json @@ -480,8 +474,8 @@ def test_basic(self): print("\n") print("\n".join(output_lines)) self.assertEqual(len(output_lines), len(expect_lines)) - for i in range(0, len(output_lines)): - self.assertEqual(expect_lines[i], output_lines[i]) + for i, output_line in enumerate(output_lines): + self.assertEqual(expect_lines[i], output_line) class TestReportDifference(unittest.TestCase): @@ -495,9 +489,9 @@ def load_results(): ) testOutput1 = os.path.join(testInputs, "test1_run1.json") testOutput2 = os.path.join(testInputs, "test1_run2.json") - with open(testOutput1, "r") as f: + with open(testOutput1) as f: json1 = json.load(f) - with open(testOutput2, "r") as f: + with open(testOutput2) as f: json2 = json.load(f) return json1, json2 @@ -584,8 +578,8 @@ def test_json_diff_report_pretty_printing(self): print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) - for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(" ") if x] + for i, output_line in enumerate(output_lines): + parts = [x for x in output_line.split(" ") if x] self.assertEqual(len(parts), 7) self.assertEqual(expect_lines[i], parts) @@ -819,7 +813,9 @@ def test_json_diff_report_output(self): }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip(self.json_diff_report, expected_output): + for out, expected in zip( + self.json_diff_report, expected_output, strict=True + ): self.assertEqual(out["name"], expected["name"]) self.assertEqual(out["label"], expected["label"]) self.assertEqual(out["time_unit"], expected["time_unit"]) @@ -837,7 +833,7 @@ def load_result(): os.path.dirname(os.path.realpath(__file__)), "Inputs" ) testOutput = os.path.join(testInputs, "test2_run.json") - with open(testOutput, "r") as f: + with open(testOutput) as f: json = json.load(f) return json @@ -861,8 +857,8 @@ def test_json_diff_report_pretty_printing(self): print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) - for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(" ") if x] + for i, output_line in enumerate(output_lines): + parts = [x for x in output_line.split(" ") if x] self.assertEqual(len(parts), 7) self.assertEqual(expect_lines[i], parts) @@ -947,7 +943,9 @@ def test_json_diff_report(self): }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip(self.json_diff_report, expected_output): + for out, expected in zip( + self.json_diff_report, expected_output, strict=True + ): self.assertEqual(out["name"], expected["name"]) self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) @@ -965,9 +963,9 @@ def load_results(): ) testOutput1 = os.path.join(testInputs, "test3_run0.json") testOutput2 = os.path.join(testInputs, "test3_run1.json") - with open(testOutput1, "r") as f: + with open(testOutput1) as f: json1 = json.load(f) - with open(testOutput2, "r") as f: + with open(testOutput2) as f: json2 = json.load(f) return json1, json2 @@ -1025,8 +1023,8 @@ def test_json_diff_report_pretty_printing(self): print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) - for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(" ") if x] + for i, output_line in enumerate(output_lines): + parts = [x for x in output_line.split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report_pretty_printing_aggregates_only(self): @@ -1081,8 +1079,8 @@ def test_json_diff_report_pretty_printing_aggregates_only(self): print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) - for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(" ") if x] + for i, output_line in enumerate(output_lines): + parts = [x for x in output_line.split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report(self): @@ -1190,7 +1188,9 @@ def test_json_diff_report(self): }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip(self.json_diff_report, expected_output): + for out, expected in zip( + self.json_diff_report, expected_output, strict=True + ): self.assertEqual(out["name"], expected["name"]) self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) @@ -1210,9 +1210,9 @@ def load_results(): ) testOutput1 = os.path.join(testInputs, "test3_run0.json") testOutput2 = os.path.join(testInputs, "test3_run1.json") - with open(testOutput1, "r") as f: + with open(testOutput1) as f: json1 = json.load(f) - with open(testOutput2, "r") as f: + with open(testOutput2) as f: json2 = json.load(f) return json1, json2 @@ -1270,8 +1270,8 @@ def test_json_diff_report_pretty_printing(self): print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) - for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(" ") if x] + for i, output_line in enumerate(output_lines): + parts = [x for x in output_line.split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report(self): @@ -1380,7 +1380,9 @@ def test_json_diff_report(self): }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip(self.json_diff_report, expected_output): + for out, expected in zip( + self.json_diff_report, expected_output, strict=True + ): self.assertEqual(out["name"], expected["name"]) self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) @@ -1398,9 +1400,9 @@ def load_results(): ) testOutput1 = os.path.join(testInputs, "test4_run0.json") testOutput2 = os.path.join(testInputs, "test4_run1.json") - with open(testOutput1, "r") as f: + with open(testOutput1) as f: json1 = json.load(f) - with open(testOutput2, "r") as f: + with open(testOutput2) as f: json2 = json.load(f) return json1, json2 @@ -1416,8 +1418,8 @@ def test_json_diff_report_pretty_printing(self): print("\n") print("\n".join(output_lines_with_header)) self.assertEqual(len(output_lines), len(expect_lines)) - for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(" ") if x] + for i, output_line in enumerate(output_lines): + parts = [x for x in output_line.split(" ") if x] self.assertEqual(expect_lines[i], parts) def test_json_diff_report(self): @@ -1439,7 +1441,9 @@ def test_json_diff_report(self): } ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip(self.json_diff_report, expected_output): + for out, expected in zip( + self.json_diff_report, expected_output, strict=True + ): self.assertEqual(out["name"], expected["name"]) self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) @@ -1456,7 +1460,7 @@ def load_result(): os.path.dirname(os.path.realpath(__file__)), "Inputs" ) testOutput = os.path.join(testInputs, "test4_run.json") - with open(testOutput, "r") as f: + with open(testOutput) as f: json = json.load(f) return json @@ -1480,13 +1484,15 @@ def test_json_diff_report_pretty_printing(self): "88 family 1 instance 1 aggregate", ] - for n in range(len(self.json["benchmarks"]) ** 2): + for _n in range(len(self.json["benchmarks"]) ** 2): random.shuffle(self.json["benchmarks"]) sorted_benchmarks = util.sort_benchmark_results(self.json)[ "benchmarks" ] self.assertEqual(len(expected_names), len(sorted_benchmarks)) - for out, expected in zip(sorted_benchmarks, expected_names): + for out, expected in zip( + sorted_benchmarks, expected_names, strict=True + ): self.assertEqual(out["name"], expected) @@ -1503,12 +1509,12 @@ def load_results(): ) testOutput1 = os.path.join(testInputs, "test5_run0.json") testOutput2 = os.path.join(testInputs, "test5_run1.json") - with open(testOutput1, "r") as f: + with open(testOutput1) as f: json1 = json.load(f) json1["benchmarks"] = [ json1["benchmarks"][0] for i in range(1000) ] - with open(testOutput2, "r") as f: + with open(testOutput2) as f: json2 = json.load(f) json2["benchmarks"] = [ json2["benchmarks"][0] for i in range(1000) @@ -1535,8 +1541,8 @@ def test_json_diff_report_pretty_printing(self): ) output_lines = output_lines_with_header[2:] found = False - for i in range(0, len(output_lines)): - parts = [x for x in output_lines[i].split(" ") if x] + for output_line in output_lines: + parts = [x for x in output_line.split(" ") if x] found = expect_line == parts if found: break @@ -1578,7 +1584,9 @@ def test_json_diff_report(self): }, ] self.assertEqual(len(self.json_diff_report), len(expected_output)) - for out, expected in zip(self.json_diff_report, expected_output): + for out, expected in zip( + self.json_diff_report, expected_output, strict=True + ): self.assertEqual(out["name"], expected["name"]) self.assertEqual(out["time_unit"], expected["time_unit"]) assert_utest(self, out, expected) @@ -1602,7 +1610,7 @@ def assert_utest(unittest_instance, lhs, rhs): def assert_measurements(unittest_instance, lhs, rhs): - for m1, m2 in zip(lhs["measurements"], rhs["measurements"]): + for m1, m2 in zip(lhs["measurements"], rhs["measurements"], strict=False): unittest_instance.assertEqual(m1["real_time"], m2["real_time"]) unittest_instance.assertEqual(m1["cpu_time"], m2["cpu_time"]) # m1['time'] and m1['cpu'] hold values which are being calculated, diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 1119a1a2ca..596b51a07c 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -46,7 +46,7 @@ def is_json_file(filename): 'False' otherwise. """ try: - with open(filename, "r") as f: + with open(filename) as f: json.load(f) return True except BaseException: @@ -97,7 +97,8 @@ def find_benchmark_flag(prefix, benchmark_flags): if it is found return the arg it specifies. If specified more than once the last value is returned. If the flag is not found None is returned. """ - assert prefix.startswith("--") and prefix.endswith("=") + assert prefix.startswith("--") + assert prefix.endswith("=") result = None for f in benchmark_flags: if f.startswith(prefix): @@ -110,7 +111,8 @@ def remove_benchmark_flags(prefix, benchmark_flags): Return a new list containing the specified benchmark_flags except those with the specified prefix. """ - assert prefix.startswith("--") and prefix.endswith("=") + assert prefix.startswith("--") + assert prefix.endswith("=") return [f for f in benchmark_flags if not f.startswith(prefix)] @@ -133,17 +135,16 @@ def benchmark_wanted(benchmark): name = benchmark.get("run_name", None) or benchmark["name"] return re.search(benchmark_filter, name) is not None - with open(fname, "r") as f: + with open(fname) as f: results = json.load(f) - if "context" in results: - if "json_schema_version" in results["context"]: - json_schema_version = results["context"]["json_schema_version"] - if json_schema_version != 1: - print( - "In %s, got unnsupported JSON schema version: %i, expected 1" - % (fname, json_schema_version) - ) - sys.exit(1) + if "json_schema_version" in results.get("context", {}): + json_schema_version = results["context"]["json_schema_version"] + if json_schema_version != 1: + print( + "In %s, got unnsupported JSON schema version: %i, expected 1" + % (fname, json_schema_version) + ) + sys.exit(1) if "benchmarks" in results: results["benchmarks"] = list( filter(benchmark_wanted, results["benchmarks"]) @@ -157,9 +158,7 @@ def sort_benchmark_results(result): # From inner key to the outer key! benchmarks = sorted( benchmarks, - key=lambda benchmark: benchmark["repetition_index"] - if "repetition_index" in benchmark - else -1, + key=lambda benchmark: benchmark.get("repetition_index", -1), ) benchmarks = sorted( benchmarks, @@ -169,15 +168,11 @@ def sort_benchmark_results(result): ) benchmarks = sorted( benchmarks, - key=lambda benchmark: benchmark["per_family_instance_index"] - if "per_family_instance_index" in benchmark - else -1, + key=lambda benchmark: benchmark.get("per_family_instance_index", -1), ) benchmarks = sorted( benchmarks, - key=lambda benchmark: benchmark["family_index"] - if "family_index" in benchmark - else -1, + key=lambda benchmark: benchmark.get("family_index", -1), ) result["benchmarks"] = benchmarks @@ -197,11 +192,12 @@ def run_benchmark(exe_name, benchmark_flags): is_temp_output = True thandle, output_name = tempfile.mkstemp() os.close(thandle) - benchmark_flags = list(benchmark_flags) + [ - "--benchmark_out=%s" % output_name + benchmark_flags = [ + *list(benchmark_flags), + "--benchmark_out=%s" % output_name, ] - cmd = [exe_name] + benchmark_flags + cmd = [exe_name, *benchmark_flags] print("RUNNING: %s" % " ".join(cmd)) exitCode = subprocess.call(cmd) if exitCode != 0: diff --git a/tools/strip_asm.py b/tools/strip_asm.py index bc3a774a79..14d80ed48d 100755 --- a/tools/strip_asm.py +++ b/tools/strip_asm.py @@ -73,16 +73,16 @@ def process_identifiers(line): parts = re.split(r"([a-zA-Z0-9_]+)", line) new_line = "" for tk in parts: - if is_identifier(tk): - if tk.startswith("__Z"): - tk = tk[1:] - elif ( + if is_identifier(tk) and ( + tk.startswith("__Z") + or ( tk.startswith("_") and len(tk) > 1 and tk[1].isalpha() and tk[1] != "Z" - ): - tk = tk[1:] + ) + ): + tk = tk[1:] new_line += tk return new_line @@ -148,7 +148,7 @@ def main(): print("ERROR: input file '%s' does not exist" % input) sys.exit(1) - with open(input, "r") as f: + with open(input) as f: contents = f.read() new_contents = process_asm(contents) with open(output, "w") as f: From 6f21075d9cc3e6664152851f4a13ae240847b3bd Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 22 Jan 2025 15:24:22 +0100 Subject: [PATCH 295/561] GitHub Actions: build-and-test on an ARM processor (#1911) [Standard GitHub-hosted runners for public repositories](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories) --> `ubuntu-22.04-arm`, `ubuntu-24.04-arm` --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d05300db06..c32e799db9 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-20.04, macos-latest] + os: [ubuntu-22.04, ubuntu-20.04, ubuntu-22.04-arm, macos-latest] build_type: ['Release', 'Debug'] compiler: ['g++', 'clang++'] lib: ['shared', 'static'] From 3d027d7e3817ec265872434378306f1e92fda9bb Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 22 Jan 2025 17:43:07 +0100 Subject: [PATCH 296/561] ruff rule E501: Fix long lines in Python code (#1910) * ruff rule E501: Fix long lines in Python code * Add missing space --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .ycm_extra_conf.py | 8 ++--- bindings/python/google_benchmark/__init__.py | 15 +++++---- bindings/python/google_benchmark/example.py | 3 +- pyproject.toml | 1 - tools/compare.py | 35 ++++++++++++++++---- tools/gbench/report.py | 16 ++++++--- tools/gbench/util.py | 8 +++-- 7 files changed, 60 insertions(+), 26 deletions(-) diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index caf257f054..ffef1b4daf 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -83,10 +83,10 @@ def IsHeaderFile(filename): def GetCompilationInfoForFile(filename): - # The compilation_commands.json file generated by CMake does not have entries - # for header files. So we do our best by asking the db for flags for a - # corresponding source file, if any. If one exists, the flags for that file - # should be good enough. + # The compilation_commands.json file generated by CMake does not have + # entries for header files. So we do our best by asking the db for flags for + # a corresponding source file, if any. If one exists, the flags for that + # file should be good enough. if IsHeaderFile(filename): basename = os.path.splitext(filename)[0] for extension in SOURCE_EXTENSIONS: diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 7006352669..3685928f21 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -60,7 +60,8 @@ class __OptionMaker: """ class Options: - """Pure data class to store options calls, along with the benchmarked function.""" + """Pure data class to store options calls, along with the benchmarked + function.""" def __init__(self, func): self.func = func @@ -83,8 +84,8 @@ def __builder_method(*args, **kwargs): def __decorator(func_or_options): options = self.make(func_or_options) options.builder_calls.append((builder_name, args, kwargs)) - # The decorator returns Options so it is not technically a decorator - # and needs a final call to @register + # The decorator returns Options so it is not technically a + # decorator and needs a final call to @register return options return __decorator @@ -93,8 +94,8 @@ def __decorator(func_or_options): # Alias for nicer API. -# We have to instantiate an object, even if stateless, to be able to use __getattr__ -# on option.range +# We have to instantiate an object, even if stateless, to be able to use +# __getattr__ on option.range option = __OptionMaker() @@ -104,8 +105,8 @@ def register(undefined=None, *, name=None): # Decorator is called without parenthesis so we return a decorator return lambda f: register(f, name=name) - # We have either the function to benchmark (simple case) or an instance of Options - # (@option._ case). + # We have either the function to benchmark (simple case) or an instance of + # Options (@option._ case). options = __OptionMaker.make(undefined) if name is None: diff --git a/bindings/python/google_benchmark/example.py b/bindings/python/google_benchmark/example.py index 5909c0fc0e..5635c41842 100644 --- a/bindings/python/google_benchmark/example.py +++ b/bindings/python/google_benchmark/example.py @@ -13,7 +13,8 @@ # limitations under the License. """Example of Python using C++ benchmark framework. -To run this example, you must first install the `google_benchmark` Python package. +To run this example, you must first install the `google_benchmark` Python +package. To install using `setup.py`, download and extract the `google_benchmark` source. In the extracted directory, execute: diff --git a/pyproject.toml b/pyproject.toml index 761473c204..4595b6dd11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,7 +70,6 @@ target-version = "py311" # Enable pycodestyle (`E`, `W`), Pyflakes (`F`), and isort (`I`) codes by default. select = ["ASYNC", "B", "C4", "C90", "E", "F", "I", "PERF", "PIE", "PT018", "RUF", "SIM", "UP", "W"] ignore = [ - "E501", # line too long "PLW2901", # redefined-loop-name "UP031", # printf-string-formatting ] diff --git a/tools/compare.py b/tools/compare.py index 36cbe07569..1dd9de239f 100755 --- a/tools/compare.py +++ b/tools/compare.py @@ -85,7 +85,10 @@ def create_parser(): "-d", "--dump_to_json", dest="dump_to_json", - help="Additionally, dump benchmark comparison output to this file in JSON format.", + help=( + "Additionally, dump benchmark comparison output to this file in" + " JSON format." + ), ) utest = parser.add_argument_group() @@ -94,7 +97,16 @@ def create_parser(): dest="utest", default=True, action="store_false", - help=f"The tool can do a two-tailed Mann-Whitney U test with the null hypothesis that it is equally likely that a randomly selected value from one sample will be less than or greater than a randomly selected value from a second sample.\nWARNING: requires **LARGE** (no less than {report.UTEST_OPTIMAL_REPETITIONS}) number of repetitions to be meaningful!\nThe test is being done by default, if at least {report.UTEST_MIN_REPETITIONS} repetitions were done.\nThis option can disable the U Test.", + help=( + "The tool can do a two-tailed Mann-Whitney U test with the null" + " hypothesis that it is equally likely that a randomly selected" + " value from one sample will be less than or greater than a" + " randomly selected value from a second sample.\nWARNING: requires" + f" **LARGE** (no less than {report.UTEST_OPTIMAL_REPETITIONS})" + " number of repetitions to be meaningful!\nThe test is being done" + f" by default, if at least {report.UTEST_MIN_REPETITIONS}" + " repetitions were done.\nThis option can disable the U Test." + ), ) alpha_default = 0.05 utest.add_argument( @@ -103,7 +115,9 @@ def create_parser(): default=alpha_default, type=float, help=( - "significance level alpha. if the calculated p-value is below this value, then the result is said to be statistically significant and the null hypothesis is rejected.\n(default: %0.4f)" + "significance level alpha. if the calculated p-value is below this" + " value, then the result is said to be statistically significant" + " and the null hypothesis is rejected.\n(default: %0.4f)" ) % alpha_default, ) @@ -114,7 +128,10 @@ def create_parser(): parser_a = subparsers.add_parser( "benchmarks", - help="The most simple use-case, compare all the output of these two benchmarks", + help=( + "The most simple use-case, compare all the output of these two" + " benchmarks" + ), ) baseline = parser_a.add_argument_group("baseline", "The benchmark baseline") baseline.add_argument( @@ -178,7 +195,10 @@ def create_parser(): parser_c = subparsers.add_parser( "benchmarksfiltered", - help="Compare filter one of first benchmark with filter two of the second benchmark", + help=( + "Compare filter one of first benchmark with filter two of the" + " second benchmark" + ), ) baseline = parser_c.add_argument_group("baseline", "The benchmark baseline") baseline.add_argument( @@ -203,7 +223,10 @@ def create_parser(): metavar="test_contender", type=argparse.FileType("r"), nargs=1, - help="The second benchmark executable or JSON output file, that will be compared against the baseline", + help=( + "The second benchmark executable or JSON output file, that will be" + " compared against the baseline" + ), ) contender.add_argument( "filter_contender", diff --git a/tools/gbench/report.py b/tools/gbench/report.py index 6b58918bfc..e143e45a71 100644 --- a/tools/gbench/report.py +++ b/tools/gbench/report.py @@ -249,7 +249,10 @@ def get_utest_color(pval): # We still got some results to show but issue a warning about it. if not utest["have_optimal_repetitions"]: dsc_color = BC_WARNING - dsc += f". WARNING: Results unreliable! {UTEST_OPTIMAL_REPETITIONS}+ repetitions recommended." + dsc += ( + f". WARNING: Results unreliable! {UTEST_OPTIMAL_REPETITIONS}+" + " repetitions recommended." + ) special_str = "{}{:<{}s}{endc}{}{:16.4f}{endc}{}{:16.4f}{endc}{} {}" @@ -397,12 +400,17 @@ def get_color(res): first_col_width = find_longest_name(json_diff_report) first_col_width = max(first_col_width, len("Benchmark")) first_col_width += len(UTEST_COL_NAME) - first_line = "{:<{}s}Time CPU Time Old Time New CPU Old CPU New".format( - "Benchmark", 12 + first_col_width + fmt_str = ( + "{:<{}s}Time CPU Time Old Time New CPU Old" + " CPU New" ) + first_line = fmt_str.format("Benchmark", 12 + first_col_width) output_strs = [first_line, "-" * len(first_line)] - fmt_str = "{}{:<{}s}{endc}{}{:+16.4f}{endc}{}{:+16.4f}{endc}{:14.0f}{:14.0f}{endc}{:14.0f}{:14.0f}" + fmt_str = ( + "{}{:<{}s}{endc}{}{:+16.4f}{endc}{}{:+16.4f}{endc}{:14.0f}{:14.0f}" + "{endc}{:14.0f}{:14.0f}" + ) for benchmark in json_diff_report: # *If* we were asked to only include aggregates, # and if it is non-aggregate, then don't print it. diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 596b51a07c..2e91006be4 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -1,4 +1,6 @@ -"""util.py - General utilities for running, loading, and processing benchmarks""" +"""util.py - General utilities for running, loading, and processing +benchmarks +""" import json import os @@ -141,8 +143,8 @@ def benchmark_wanted(benchmark): json_schema_version = results["context"]["json_schema_version"] if json_schema_version != 1: print( - "In %s, got unnsupported JSON schema version: %i, expected 1" - % (fname, json_schema_version) + f"In {fname}, got unnsupported JSON schema version:" + f" {json_schema_version}, expected 1" ) sys.exit(1) if "benchmarks" in results: From 049f6e79cc3e8636cec21bbd94ed185b4a5f2653 Mon Sep 17 00:00:00 2001 From: xdje42 Date: Wed, 29 Jan 2025 01:53:56 -0800 Subject: [PATCH 297/561] [BUG] Run external profiler (ProfilerManager) same number of iterations #1913 (#1914) Run the external profiler the same number of iterations as the benchmark was run normally. This makes, for example, a trace collected via ProfilerManager consistent with collected PMU data. --- src/benchmark_runner.cc | 9 ++-- src/benchmark_runner.h | 2 +- test/CMakeLists.txt | 3 ++ test/profiler_manager_iterations_test.cc | 61 ++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 test/profiler_manager_iterations_test.cc diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 463f69fc52..3e8aea7376 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -438,9 +438,7 @@ MemoryManager::Result* BenchmarkRunner::RunMemoryManager( return memory_result; } -void BenchmarkRunner::RunProfilerManager() { - // TODO: Provide a way to specify the number of iterations. - IterationCount profile_iterations = 1; +void BenchmarkRunner::RunProfilerManager(IterationCount profile_iterations) { std::unique_ptr manager; manager.reset(new internal::ThreadManager(1)); b.Setup(); @@ -507,7 +505,10 @@ void BenchmarkRunner::DoOneRepetition() { } if (profiler_manager != nullptr) { - RunProfilerManager(); + // We want to externally profile the benchmark for the same number of + // iterations because, for example, if we're tracing the benchmark then we + // want trace data to reasonably match PMU data. + RunProfilerManager(iters); } // Ok, now actually report. diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index 6e5ceb31e0..332bbb51ec 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -109,7 +109,7 @@ class BenchmarkRunner { MemoryManager::Result* RunMemoryManager(IterationCount memory_iterations); - void RunProfilerManager(); + void RunProfilerManager(IterationCount profile_iterations); IterationCount PredictNumItersNeeded(const IterationResults& i) const; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 321e24d94b..3e2c651830 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -195,6 +195,9 @@ benchmark_add_test(NAME memory_manager_test COMMAND memory_manager_test --benchm compile_output_test(profiler_manager_test) benchmark_add_test(NAME profiler_manager_test COMMAND profiler_manager_test --benchmark_min_time=0.01s) +compile_benchmark_test(profiler_manager_iterations_test) +benchmark_add_test(NAME profiler_manager_iterations COMMAND profiler_manager_iterations_test) + # MSVC does not allow to set the language standard to C++98/03. if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) compile_benchmark_test(cxx03_test) diff --git a/test/profiler_manager_iterations_test.cc b/test/profiler_manager_iterations_test.cc new file mode 100644 index 0000000000..e727929ddb --- /dev/null +++ b/test/profiler_manager_iterations_test.cc @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +#include "benchmark/benchmark.h" + +// Tests that we can specify the number of profiler iterations with +// --benchmark_min_time=x. +namespace { + +int iteration_count = 0; +int end_profiler_iteration_count = 0; + +class TestProfilerManager : public benchmark::ProfilerManager { + void AfterSetupStart() override { iteration_count = 0; } + void BeforeTeardownStop() override { + end_profiler_iteration_count = iteration_count; + } +}; + +class NullReporter : public benchmark::BenchmarkReporter { + public: + bool ReportContext(const Context& /*context*/) override { return true; } + void ReportRuns(const std::vector& /* report */) override {} +}; + +} // end namespace + +static void BM_MyBench(benchmark::State& state) { + for (auto s : state) { + ++iteration_count; + } +} +BENCHMARK(BM_MyBench); + +int main(int argc, char** argv) { + // Make a fake argv and append the new --benchmark_profiler_iterations= + // to it. + int fake_argc = argc + 1; + const char** fake_argv = new const char*[static_cast(fake_argc)]; + for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; + fake_argv[argc] = "--benchmark_min_time=4x"; + + std::unique_ptr pm(new TestProfilerManager()); + benchmark::RegisterProfilerManager(pm.get()); + + benchmark::Initialize(&fake_argc, const_cast(fake_argv)); + + NullReporter null_reporter; + const size_t returned_count = + benchmark::RunSpecifiedBenchmarks(&null_reporter, "BM_MyBench"); + assert(returned_count == 1); + + // Check the executed iters. + assert(end_profiler_iteration_count == 4); + + benchmark::RegisterProfilerManager(nullptr); + delete[] fake_argv; + return 0; +} From 4642758438659e01fed407b28062d88b70d31331 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 30 Jan 2025 09:52:07 +0000 Subject: [PATCH 298/561] fix some clang-tidy issues --- src/benchmark_runner.h | 1 - test/profiler_manager_test.cc | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index 332bbb51ec..20a37c1ae3 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -19,7 +19,6 @@ #include #include "benchmark_api_internal.h" -#include "internal_macros.h" #include "perf_counters.h" #include "thread_manager.h" diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc index 3b08a60d1d..21f2f1dc03 100644 --- a/test/profiler_manager_test.cc +++ b/test/profiler_manager_test.cc @@ -1,5 +1,6 @@ // FIXME: WIP +#include #include #include "benchmark/benchmark.h" From 4a805f9f0f468bd4d499d060a1a1c6bd5d6b6b73 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Thu, 30 Jan 2025 10:00:04 +0000 Subject: [PATCH 299/561] clang-tidy warning --- src/string_util.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/string_util.h b/src/string_util.h index 731aa2c04c..f1e50be4f4 100644 --- a/src/string_util.h +++ b/src/string_util.h @@ -9,7 +9,6 @@ #include "benchmark/benchmark.h" #include "benchmark/export.h" #include "check.h" -#include "internal_macros.h" namespace benchmark { From c35af58b61daa111c93924e0e7b65022871fadac Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Tue, 4 Feb 2025 05:32:41 -0500 Subject: [PATCH 300/561] Update error message now that /proc/cpuinfo is no longer in use (#1917) c24774dc4f4402c3ad150363321cc972ed2669e7 removed using /proc/cpuinfo so no longer mention it in the error message. --- src/sysinfo.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index eddd430e68..2787e87c8e 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -515,8 +515,7 @@ int GetNumCPUsImpl() { int GetNumCPUs() { int num_cpus = GetNumCPUsImpl(); if (num_cpus < 1) { - std::cerr << "Unable to extract number of CPUs. If your platform uses " - "/proc/cpuinfo, custom support may need to be added.\n"; + std::cerr << "Unable to extract number of CPUs.\n"; /* There is at least one CPU which we run on. */ num_cpus = 1; } From 2e16afc3fd53586f9949aa347c4bb909d15523a5 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 5 Feb 2025 12:21:47 +0000 Subject: [PATCH 301/561] add back /proc/cpuinfo as a fallback for some platforms (#1918) --- src/sysinfo.cc | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 2787e87c8e..4fb32615bd 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -508,6 +508,55 @@ int GetNumCPUsImpl() { hardware_threads.max_hthreads = 1; } return hardware_threads.max_hthreads; +#else + // Fallback for platforms (such as WASM) that aren't covered above. + int num_cpus = 0; + int max_id = -1; + std::ifstream f("/proc/cpuinfo"); + if (!f.is_open()) { + std::cerr << "Failed to open /proc/cpuinfo\n"; + return -1; + } +#if defined(__alpha__) + const std::string Key = "cpus detected"; +#else + const std::string Key = "processor"; +#endif + std::string ln; + while (std::getline(f, ln)) { + if (ln.empty()) continue; + std::size_t split_idx = ln.find(':'); + std::string value; +#if defined(__s390__) + // s390 has another format in /proc/cpuinfo + // it needs to be parsed differently + if (split_idx != std::string::npos) + value = ln.substr(Key.size() + 1, split_idx - Key.size() - 1); +#else + if (split_idx != std::string::npos) value = ln.substr(split_idx + 1); +#endif + if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) { + num_cpus++; + if (!value.empty()) { + const int cur_id = benchmark::stoi(value); + max_id = std::max(cur_id, max_id); + } + } + } + if (f.bad()) { + PrintErrorAndDie("Failure reading /proc/cpuinfo"); + } + if (!f.eof()) { + PrintErrorAndDie("Failed to read to end of /proc/cpuinfo"); + } + f.close(); + + if ((max_id + 1) != num_cpus) { + fprintf(stderr, + "CPU ID assignments in /proc/cpuinfo seem messed up." + " This is usually caused by a bad BIOS.\n"); + } + return num_cpus; #endif BENCHMARK_UNREACHABLE(); } @@ -516,7 +565,7 @@ int GetNumCPUs() { int num_cpus = GetNumCPUsImpl(); if (num_cpus < 1) { std::cerr << "Unable to extract number of CPUs.\n"; - /* There is at least one CPU which we run on. */ + // There must be at least one CPU on which we're running. num_cpus = 1; } return num_cpus; From 47bc26c8b5ca1f043641ec51d54858402807d107 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:45:30 +0000 Subject: [PATCH 302/561] change pacboy compiler target for windows builds (#1915) * change pacboy compiler target for windows builds * use an action for cmake instead of doing things manually * set compiler for cmake * remove cmake action from msys2 build * readd cmake package for msys2 * fix cmake test path to match build * fix msvc build type setting * fix msvc build type setting * consistent output directory for msvc * remove legacy environments (https://www.msys2.org/docs/environments/\#__tabbed_1_2) * remove shell overrides and depend on default for msys2 --- .github/workflows/build-and-test.yml | 61 ++++++++++------------------ 1 file changed, 22 insertions(+), 39 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c32e799db9..8394d10129 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -25,33 +25,18 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: lukka/get-cmake@latest - - - name: create build environment - run: cmake -E make_directory ${{ runner.workspace }}/_build - - - name: setup cmake initial cache - run: touch compiler-cache.cmake - - - name: configure cmake - env: - CXX: ${{ matrix.compiler }} - shell: bash - working-directory: ${{ runner.workspace }}/_build - run: > - cmake -C ${{ github.workspace }}/compiler-cache.cmake - $GITHUB_WORKSPACE - -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON - -DBUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - -DCMAKE_CXX_COMPILER=${{ env.CXX }} - -DCMAKE_CXX_VISIBILITY_PRESET=hidden - -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON - - name: build - shell: bash - working-directory: ${{ runner.workspace }}/_build - run: cmake --build . --config ${{ matrix.build_type }} + uses: threeal/cmake-action@v2.1.0 + with: + build-dir: ${{ runner.workspace }}/_build + cxx-compiler: ${{ matrix.compiler }} + options: | + BENCHMARK_DOWNLOAD_DEPENDENCIES=ON + BUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} + CMAKE_BUILD_TYPE=${{ matrix.build_type }} + CMAKE_CXX_COMPILER=${{ matrix.compiler }} + CMAKE_CXX_VISIBILITY_PRESET=hidden + CMAKE_VISIBILITY_INLINES_HIDDEN=ON - name: test shell: bash @@ -70,8 +55,6 @@ jobs: msvc: - VS-16-2019 - VS-17-2022 - arch: - - x64 build_type: - Debug - Release @@ -93,17 +76,16 @@ jobs: - name: configure cmake run: > - cmake -S . -B _build/ - -A ${{ matrix.arch }} + cmake -S . -B ${{ runner.workspace }}/_build/ -G "${{ matrix.generator }}" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} - name: build - run: cmake --build _build/ --config ${{ matrix.build_type }} + run: cmake --build ${{ runner.workspace }}/_build/ --config ${{ matrix.build_type }} - name: test - run: ctest --test-dir _build/ -C ${{ matrix.build_type }} -VV + run: ctest --test-dir ${{ runner.workspace }}/_build/ -C ${{ matrix.build_type }} -VV msys2: name: ${{ matrix.os }}.${{ matrix.build_type }}.${{ matrix.lib }}.${{ matrix.msys2.msystem }} @@ -117,9 +99,7 @@ jobs: os: [ windows-latest ] msys2: - { msystem: MINGW64, arch: x86_64, family: GNU, compiler: g++ } - - { msystem: MINGW32, arch: i686, family: GNU, compiler: g++ } - { msystem: CLANG64, arch: x86_64, family: LLVM, compiler: clang++ } - - { msystem: CLANG32, arch: i686, family: LLVM, compiler: clang++ } - { msystem: UCRT64, arch: x86_64, family: GNU, compiler: g++ } build_type: - Debug @@ -129,9 +109,7 @@ jobs: - static steps: - - uses: actions/checkout@v4 - - - name: Install Base Dependencies + - name: setup msys2 uses: msys2/setup-msys2@v2 with: cache: false @@ -141,10 +119,14 @@ jobs: git base-devel pacboy: >- - cc:p + gcc:p + clang:p cmake:p ninja:p + - uses: actions/checkout@v4 + + # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake env: CXX: ${{ matrix.msys2.compiler }} @@ -158,4 +140,5 @@ jobs: run: cmake --build _build/ --config ${{ matrix.build_type }} - name: test - run: ctest --test-dir _build/ -C ${{ matrix.build_type }} -VV + working-directory: _build + run: ctest -C ${{ matrix.build_type }} -VV From 41e81b1ca4bbb41d234f2d0f2c56591db78ebb83 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 6 Feb 2025 05:10:55 -0500 Subject: [PATCH 303/561] Retrieve the number of online CPUs on OpenBSD and NetBSD (#1916) * Retrieve the number of online CPUs on OpenBSD and NetBSD * Spacing adjustment --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/sysinfo.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 4fb32615bd..6232c8c67f 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -153,11 +153,11 @@ ValueUnion GetSysctlImp(std::string const& name) { int mib[2]; mib[0] = CTL_HW; - if ((name == "hw.ncpu") || (name == "hw.cpuspeed")) { + if ((name == "hw.ncpuonline") || (name == "hw.cpuspeed")) { ValueUnion buff(sizeof(int)); - if (name == "hw.ncpu") { - mib[1] = HW_NCPU; + if (name == "hw.ncpuonline") { + mib[1] = HW_NCPUONLINE; } else { mib[1] = HW_CPUSPEED; } @@ -482,7 +482,13 @@ std::string GetSystemName() { int GetNumCPUsImpl() { #ifdef BENCHMARK_HAS_SYSCTL int num_cpu = -1; - if (GetSysctl("hw.ncpu", &num_cpu)) return num_cpu; + constexpr auto* hwncpu = +#ifdef HW_NCPUONLINE + "hw.ncpuonline"; +#else + "hw.ncpu"; +#endif + if (GetSysctl(hwncpu, &num_cpu)) return num_cpu; PrintErrorAndDie("Err: ", strerror(errno)); #elif defined(BENCHMARK_OS_WINDOWS) SYSTEM_INFO sysinfo; From faaa266d33ff203e28b31dd31be9f90c29f28d04 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 6 Feb 2025 05:53:21 -0500 Subject: [PATCH 304/561] Replace usage of deprecated sysctl on macOS (#1919) The use of the sysctl hw.ncpu has long been deprecated and should be replaced by hw.logicalcpu. --- src/sysinfo.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 6232c8c67f..1d0618ed2f 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -483,7 +483,9 @@ int GetNumCPUsImpl() { #ifdef BENCHMARK_HAS_SYSCTL int num_cpu = -1; constexpr auto* hwncpu = -#ifdef HW_NCPUONLINE +#if defined BENCHMARK_OS_MACOSX + "hw.logicalcpu"; +#elif defined(HW_NCPUONLINE) "hw.ncpuonline"; #else "hw.ncpu"; From edb1e76d8cb080a396c7c992e5d4023e1a777bd1 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 6 Feb 2025 07:54:17 -0500 Subject: [PATCH 305/561] Try to use the _SC_NPROCESSORS_ONLN sysconf elsewhere (#1920) Try to use the sysconf method on other OS's other than just Linux and Solaris if it exists. Also slight shuffling of the order of sysctl and sysconf methods. --- src/sysinfo.cc | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 1d0618ed2f..6d191af5ac 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -480,7 +480,23 @@ std::string GetSystemName() { } int GetNumCPUsImpl() { -#ifdef BENCHMARK_HAS_SYSCTL +#ifdef BENCHMARK_OS_WINDOWS + SYSTEM_INFO sysinfo; + // Use memset as opposed to = {} to avoid GCC missing initializer false + // positives. + std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO)); + GetSystemInfo(&sysinfo); + // number of logical processors in the current group + return static_cast(sysinfo.dwNumberOfProcessors); +#elif defined(BENCHMARK_OS_QNX) + return static_cast(_syspage_ptr->num_cpu); +#elif defined(BENCHMARK_OS_QURT) + qurt_sysenv_max_hthreads_t hardware_threads; + if (qurt_sysenv_get_max_hw_threads(&hardware_threads) != QURT_EOK) { + hardware_threads.max_hthreads = 1; + } + return hardware_threads.max_hthreads; +#elif defined(BENCHMARK_HAS_SYSCTL) int num_cpu = -1; constexpr auto* hwncpu = #if defined BENCHMARK_OS_MACOSX @@ -492,15 +508,7 @@ int GetNumCPUsImpl() { #endif if (GetSysctl(hwncpu, &num_cpu)) return num_cpu; PrintErrorAndDie("Err: ", strerror(errno)); -#elif defined(BENCHMARK_OS_WINDOWS) - SYSTEM_INFO sysinfo; - // Use memset as opposed to = {} to avoid GCC missing initializer false - // positives. - std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO)); - GetSystemInfo(&sysinfo); - // number of logical processors in the current group - return static_cast(sysinfo.dwNumberOfProcessors); -#elif defined(__linux__) || defined(BENCHMARK_OS_SOLARIS) +#elif defined(_SC_NPROCESSORS_ONLN) // Returns -1 in case of a failure. int num_cpu = static_cast(sysconf(_SC_NPROCESSORS_ONLN)); if (num_cpu < 0) { @@ -508,14 +516,6 @@ int GetNumCPUsImpl() { strerror(errno)); } return num_cpu; -#elif defined(BENCHMARK_OS_QNX) - return static_cast(_syspage_ptr->num_cpu); -#elif defined(BENCHMARK_OS_QURT) - qurt_sysenv_max_hthreads_t hardware_threads; - if (qurt_sysenv_get_max_hw_threads(&hardware_threads) != QURT_EOK) { - hardware_threads.max_hthreads = 1; - } - return hardware_threads.max_hthreads; #else // Fallback for platforms (such as WASM) that aren't covered above. int num_cpus = 0; From 9d8201efd4cbbe6271d0579ec2047dbfc396d22d Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:03:14 +0000 Subject: [PATCH 306/561] fix sanitizer cmake builds (#1906) * bump llvm version to 19 * use same standard for feature checks as for the build --- .github/libcxx-setup.sh | 2 +- .github/workflows/sanitizer.yml | 2 +- cmake/CXXFeatureCheck.cmake | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/libcxx-setup.sh b/.github/libcxx-setup.sh index 9aaf96af4b..eacc982714 100755 --- a/.github/libcxx-setup.sh +++ b/.github/libcxx-setup.sh @@ -3,7 +3,7 @@ set -e # Checkout LLVM sources -git clone --depth=1 --branch llvmorg-16.0.6 https://github.com/llvm/llvm-project.git llvm-project +git clone --depth=1 --branch llvmorg-19.1.6 https://github.com/llvm/llvm-project.git llvm-project ## Setup libc++ options if [ -z "$BUILD_32_BITS" ]; then diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 499215331a..dcf373a83e 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -65,7 +65,7 @@ jobs: if: matrix.sanitizer != 'asan' run: | "${GITHUB_WORKSPACE}/.github/libcxx-setup.sh" - echo "EXTRA_CXX_FLAGS=-stdlib=libc++ -L ${GITHUB_WORKSPACE}/llvm-build/lib -lc++abi -Isystem${GITHUB_WORKSPACE}/llvm-build/include -Isystem${GITHUB_WORKSPACE}/llvm-build/include/c++/v1 -Wl,-rpath,${GITHUB_WORKSPACE}/llvm-build/lib" >> $GITHUB_ENV + echo "EXTRA_CXX_FLAGS=-stdlib=libc++ -L${GITHUB_WORKSPACE}/llvm-build/lib -lc++abi -I${GITHUB_WORKSPACE}/llvm-build/include/c++/v1 -Isystem${GITHUB_WORKSPACE}/llvm-build/include/c++/v1 -Wl,-rpath,${GITHUB_WORKSPACE}/llvm-build/lib" >> $GITHUB_ENV - name: create build environment run: cmake -E make_directory ${{ runner.workspace }}/_build diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index e51482659b..0dfe93dc0d 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -40,7 +40,7 @@ function(cxx_feature_check FILE) message(STATUS "Cross-compiling to test ${FEATURE}") try_compile(COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CXX_STANDARD 11 + CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} @@ -56,7 +56,7 @@ function(cxx_feature_check FILE) message(STATUS "Compiling and running to test ${FEATURE}") try_run(RUN_${FEATURE} COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CXX_STANDARD 11 + CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} From da9d68953b07dc2add3fd09d55ee8fad2ac38520 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Mon, 10 Feb 2025 12:34:29 -0500 Subject: [PATCH 307/561] Remove /proc/cpuinfo fallback path (#1921) AIX, WASM (fork of musl for libc) and a few others should now use the sysconf path. /proc is not portable and cpuinfo is Linux specific. It does not work anywhere else. --- src/sysinfo.cc | 52 ++++---------------------------------------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 6d191af5ac..2b8252032b 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -497,6 +497,7 @@ int GetNumCPUsImpl() { } return hardware_threads.max_hthreads; #elif defined(BENCHMARK_HAS_SYSCTL) + // *BSD, macOS int num_cpu = -1; constexpr auto* hwncpu = #if defined BENCHMARK_OS_MACOSX @@ -509,6 +510,7 @@ int GetNumCPUsImpl() { if (GetSysctl(hwncpu, &num_cpu)) return num_cpu; PrintErrorAndDie("Err: ", strerror(errno)); #elif defined(_SC_NPROCESSORS_ONLN) + // Linux, Solaris, AIX, Haiku, WASM, etc. // Returns -1 in case of a failure. int num_cpu = static_cast(sysconf(_SC_NPROCESSORS_ONLN)); if (num_cpu < 0) { @@ -517,54 +519,8 @@ int GetNumCPUsImpl() { } return num_cpu; #else - // Fallback for platforms (such as WASM) that aren't covered above. - int num_cpus = 0; - int max_id = -1; - std::ifstream f("/proc/cpuinfo"); - if (!f.is_open()) { - std::cerr << "Failed to open /proc/cpuinfo\n"; - return -1; - } -#if defined(__alpha__) - const std::string Key = "cpus detected"; -#else - const std::string Key = "processor"; -#endif - std::string ln; - while (std::getline(f, ln)) { - if (ln.empty()) continue; - std::size_t split_idx = ln.find(':'); - std::string value; -#if defined(__s390__) - // s390 has another format in /proc/cpuinfo - // it needs to be parsed differently - if (split_idx != std::string::npos) - value = ln.substr(Key.size() + 1, split_idx - Key.size() - 1); -#else - if (split_idx != std::string::npos) value = ln.substr(split_idx + 1); -#endif - if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) { - num_cpus++; - if (!value.empty()) { - const int cur_id = benchmark::stoi(value); - max_id = std::max(cur_id, max_id); - } - } - } - if (f.bad()) { - PrintErrorAndDie("Failure reading /proc/cpuinfo"); - } - if (!f.eof()) { - PrintErrorAndDie("Failed to read to end of /proc/cpuinfo"); - } - f.close(); - - if ((max_id + 1) != num_cpus) { - fprintf(stderr, - "CPU ID assignments in /proc/cpuinfo seem messed up." - " This is usually caused by a bad BIOS.\n"); - } - return num_cpus; + // Fallback, no other API exists. + return -1; #endif BENCHMARK_UNREACHABLE(); } From 933e6d3c1f38b13f2e4fe4e795e61034d9181bee Mon Sep 17 00:00:00 2001 From: UebelAndre Date: Mon, 10 Feb 2025 14:00:14 -0800 Subject: [PATCH 308/561] Build `libpfm` with `rules_cc` (#1922) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- MODULE.bazel | 3 +- WORKSPACE | 4 - bazel/benchmark_deps.bzl | 8 -- tools/libpfm.BUILD.bazel | 235 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 229 insertions(+), 21 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 62a3aa8ba4..d8c93905f6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,13 +5,12 @@ module( bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "platforms", version = "0.0.10") -bazel_dep(name = "rules_foreign_cc", version = "0.10.1") bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_python", version = "1.0.0", dev_dependency = True) bazel_dep(name = "googletest", version = "1.14.0", dev_dependency = True, repo_name = "com_google_googletest") -bazel_dep(name = "libpfm", version = "4.11.0") +bazel_dep(name = "libpfm", version = "4.11.0.bcr.1") # Register a toolchain for Python 3.9 to be able to build numpy. Python # versions >=3.10 are problematic. diff --git a/WORKSPACE b/WORKSPACE index 503202465e..dca4850930 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -4,10 +4,6 @@ load("//:bazel/benchmark_deps.bzl", "benchmark_deps") benchmark_deps() -load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") - -rules_foreign_cc_dependencies() - load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories() diff --git a/bazel/benchmark_deps.bzl b/bazel/benchmark_deps.bzl index cb908cd514..a6be602413 100644 --- a/bazel/benchmark_deps.bzl +++ b/bazel/benchmark_deps.bzl @@ -18,14 +18,6 @@ def benchmark_deps(): ], ) - if "rules_foreign_cc" not in native.existing_rules(): - http_archive( - name = "rules_foreign_cc", - sha256 = "476303bd0f1b04cc311fc258f1708a5f6ef82d3091e53fd1977fa20383425a6a", - strip_prefix = "rules_foreign_cc-0.10.1", - url = "https://github.com/bazelbuild/rules_foreign_cc/releases/download/0.10.1/rules_foreign_cc-0.10.1.tar.gz", - ) - if "rules_python" not in native.existing_rules(): http_archive( name = "rules_python", diff --git a/tools/libpfm.BUILD.bazel b/tools/libpfm.BUILD.bazel index 4ef112352f..30b585452d 100644 --- a/tools/libpfm.BUILD.bazel +++ b/tools/libpfm.BUILD.bazel @@ -1,20 +1,241 @@ """Build rule for libpfm, which is required to collect performance counters for BENCHMARK_ENABLE_LIBPFM builds.""" -load("@rules_foreign_cc//foreign_cc:defs.bzl", "make") +load("@rules_cc//cc:defs.bzl", "cc_library") + +AARCH32_SRCS_COMMON = [ + "lib/pfmlib_arm.c", + "lib/pfmlib_arm_armv7_pmuv1.c", + "lib/pfmlib_arm_armv6.c", + "lib/pfmlib_arm_armv8.c", + "lib/pfmlib_tx2_unc_perf_event.c", +] + +AARCH32_SRCS_LINUX = [ + "lib/pfmlib_arm_perf_event.c", +] + +AARCH64_SRCS_COMMON = [ + "lib/pfmlib_arm.c", + "lib/pfmlib_arm_armv8.c", + "lib/pfmlib_tx2_unc_perf_event.c", +] + +AARCH64_SRCS_LINUX = [ + "lib/pfmlib_arm_perf_event.c", +] + +MIPS_SRCS_COMMON = [ + "lib/pfmlib_mips.c", + "lib/pfmlib_mips_74k.c", +] + +MIPS_SRCS_LINUX = [ + "lib/pfmlib_mips_perf_event.c", +] + +POWERPC_SRCS_COMMON = [ + "lib/pfmlib_powerpc.c", + "lib/pfmlib_power4.c", + "lib/pfmlib_ppc970.c", + "lib/pfmlib_power5.c", + "lib/pfmlib_power6.c", + "lib/pfmlib_power7.c", + "lib/pfmlib_torrent.c", + "lib/pfmlib_power8.c", + "lib/pfmlib_power9.c", + "lib/pfmlib_powerpc_nest.c", +] + +POWERPC_SRCS_LINUX = [ + "lib/pfmlib_powerpc_perf_event.c", +] + +S390X_SRCS_COMMON = [ + "lib/pfmlib_s390x_cpumf.c", +] + +S390X_SRCS_LINUX = [ + "lib/pfmlib_s390x_perf_event.c", +] + +X86_64_SRCS_COMMON = [ + "lib/pfmlib_amd64.c", + "lib/pfmlib_intel_core.c", + "lib/pfmlib_intel_x86.c", + "lib/pfmlib_intel_x86_arch.c", + "lib/pfmlib_intel_atom.c", + "lib/pfmlib_intel_nhm_unc.c", + "lib/pfmlib_intel_nhm.c", + "lib/pfmlib_intel_wsm.c", + "lib/pfmlib_intel_snb.c", + "lib/pfmlib_intel_snb_unc.c", + "lib/pfmlib_intel_ivb.c", + "lib/pfmlib_intel_ivb_unc.c", + "lib/pfmlib_intel_hsw.c", + "lib/pfmlib_intel_bdw.c", + "lib/pfmlib_intel_skl.c", + "lib/pfmlib_intel_icl.c", + "lib/pfmlib_intel_rapl.c", + "lib/pfmlib_intel_snbep_unc.c", + "lib/pfmlib_intel_snbep_unc_cbo.c", + "lib/pfmlib_intel_snbep_unc_ha.c", + "lib/pfmlib_intel_snbep_unc_imc.c", + "lib/pfmlib_intel_snbep_unc_pcu.c", + "lib/pfmlib_intel_snbep_unc_qpi.c", + "lib/pfmlib_intel_snbep_unc_ubo.c", + "lib/pfmlib_intel_snbep_unc_r2pcie.c", + "lib/pfmlib_intel_snbep_unc_r3qpi.c", + "lib/pfmlib_intel_ivbep_unc_cbo.c", + "lib/pfmlib_intel_ivbep_unc_ha.c", + "lib/pfmlib_intel_ivbep_unc_imc.c", + "lib/pfmlib_intel_ivbep_unc_pcu.c", + "lib/pfmlib_intel_ivbep_unc_qpi.c", + "lib/pfmlib_intel_ivbep_unc_ubo.c", + "lib/pfmlib_intel_ivbep_unc_r2pcie.c", + "lib/pfmlib_intel_ivbep_unc_r3qpi.c", + "lib/pfmlib_intel_ivbep_unc_irp.c", + "lib/pfmlib_intel_hswep_unc_cbo.c", + "lib/pfmlib_intel_hswep_unc_ha.c", + "lib/pfmlib_intel_hswep_unc_imc.c", + "lib/pfmlib_intel_hswep_unc_pcu.c", + "lib/pfmlib_intel_hswep_unc_qpi.c", + "lib/pfmlib_intel_hswep_unc_ubo.c", + "lib/pfmlib_intel_hswep_unc_r2pcie.c", + "lib/pfmlib_intel_hswep_unc_r3qpi.c", + "lib/pfmlib_intel_hswep_unc_irp.c", + "lib/pfmlib_intel_hswep_unc_sbo.c", + "lib/pfmlib_intel_bdx_unc_cbo.c", + "lib/pfmlib_intel_bdx_unc_ubo.c", + "lib/pfmlib_intel_bdx_unc_sbo.c", + "lib/pfmlib_intel_bdx_unc_ha.c", + "lib/pfmlib_intel_bdx_unc_imc.c", + "lib/pfmlib_intel_bdx_unc_irp.c", + "lib/pfmlib_intel_bdx_unc_pcu.c", + "lib/pfmlib_intel_bdx_unc_qpi.c", + "lib/pfmlib_intel_bdx_unc_r2pcie.c", + "lib/pfmlib_intel_bdx_unc_r3qpi.c", + "lib/pfmlib_intel_skx_unc_cha.c", + "lib/pfmlib_intel_skx_unc_iio.c", + "lib/pfmlib_intel_skx_unc_imc.c", + "lib/pfmlib_intel_skx_unc_irp.c", + "lib/pfmlib_intel_skx_unc_m2m.c", + "lib/pfmlib_intel_skx_unc_m3upi.c", + "lib/pfmlib_intel_skx_unc_pcu.c", + "lib/pfmlib_intel_skx_unc_ubo.c", + "lib/pfmlib_intel_skx_unc_upi.c", + "lib/pfmlib_intel_knc.c", + "lib/pfmlib_intel_slm.c", + "lib/pfmlib_intel_tmt.c", + "lib/pfmlib_intel_knl.c", + "lib/pfmlib_intel_knl_unc_imc.c", + "lib/pfmlib_intel_knl_unc_edc.c", + "lib/pfmlib_intel_knl_unc_cha.c", + "lib/pfmlib_intel_knl_unc_m2pcie.c", + "lib/pfmlib_intel_glm.c", + "lib/pfmlib_intel_netburst.c", + "lib/pfmlib_amd64_k7.c", + "lib/pfmlib_amd64_k8.c", + "lib/pfmlib_amd64_fam10h.c", + "lib/pfmlib_amd64_fam11h.c", + "lib/pfmlib_amd64_fam12h.c", + "lib/pfmlib_amd64_fam14h.c", + "lib/pfmlib_amd64_fam15h.c", + "lib/pfmlib_amd64_fam17h.c", + "lib/pfmlib_amd64_fam16h.c", +] + +X86_SRCS_COMMON = X86_64_SRCS_COMMON + [ + "lib/pfmlib_intel_coreduo.c", + "lib/pfmlib_intel_p6.c", +] filegroup( - name = "pfm_srcs", - srcs = glob(["**"]), + name = "cpu_srcs", + srcs = select({ + "@platforms//cpu:x86_32": X86_SRCS_COMMON, + "@platforms//cpu:x86_64": X86_64_SRCS_COMMON, + "@platforms//cpu:aarch32": AARCH32_SRCS_COMMON, + "@platforms//cpu:aarch64": AARCH64_SRCS_COMMON, + "@platforms//cpu:mips64": MIPS_SRCS_COMMON, + "@platforms//cpu:ppc32": POWERPC_SRCS_COMMON, + "@platforms//cpu:ppc64le": POWERPC_SRCS_COMMON, + "@platforms//cpu:ppc": POWERPC_SRCS_COMMON, + "@platforms//cpu:s390x": S390X_SRCS_COMMON, + "//conditions:default": [], + }), ) -make( - name = "libpfm", - lib_source = ":pfm_srcs", - lib_name = "libpfm", +filegroup( + name = "linux_srcs", + srcs = select({ + "@platforms//cpu:aarch32": AARCH32_SRCS_LINUX, + "@platforms//cpu:aarch64": AARCH64_SRCS_LINUX, + "@platforms//cpu:mips64": MIPS_SRCS_LINUX, + "@platforms//cpu:ppc32": POWERPC_SRCS_LINUX, + "@platforms//cpu:ppc64le": POWERPC_SRCS_LINUX, + "@platforms//cpu:ppc": POWERPC_SRCS_LINUX, + "@platforms//cpu:s390x": S390X_SRCS_LINUX, + "//conditions:default": [], + }), +) + +filegroup( + name = "srcs", + srcs = [ + "lib/pfmlib_common.c", + "lib/pfmlib_perf_event.c", + "lib/pfmlib_perf_event_pmu.c", + "lib/pfmlib_perf_event_priv.h", + "lib/pfmlib_perf_event_raw.c", + "lib/pfmlib_torrent.c", + "lib/pfmlib_tx2_unc_perf_event.c", + ":cpu_srcs", + ] + select({ + "@platforms//os:linux": [":linux_srcs"], + "//conditions:default": [], + }), +) + +cc_library( + name = "pfm", + srcs = [ + ":srcs", + ], + hdrs = glob([ + "include/perfmon/*.h", + ]), copts = [ "-Wno-format-truncation", "-Wno-use-after-free", + "-fPIC", + "-D_REENTRANT", + "-fvisibility=hidden", + ] + select({ + "@platforms//cpu:aarch32": ["-DCONFIG_PFMLIB_ARCH_ARM"], + "@platforms//cpu:aarch64": ["-DCONFIG_PFMLIB_ARCH_ARM64"], + "@platforms//cpu:mips64": ["-DCONFIG_PFMLIB_ARCH_MIPS"], + "@platforms//cpu:ppc32": ["-DCONFIG_PFMLIB_ARCH_POWERPC"], + "@platforms//cpu:ppc64le": ["-DCONFIG_PFMLIB_ARCH_POWERPC"], + "@platforms//cpu:ppc": ["-DCONFIG_PFMLIB_ARCH_POWERPC"], + "@platforms//cpu:s390x": ["-DCONFIG_PFMLIB_ARCH_S390X"], + "//conditions:default": [], + }), + includes = [ + "include", + "lib", ], + strip_include_prefix = "include", + textual_hdrs = glob([ + "lib/**/*.h", + ]), + visibility = [ + "//visibility:public", + ], +) + +alias( + name = "libpfm", + actual = ":pfm", visibility = [ "//visibility:public", ], From 835365f99a0b9ec338b6748f5ccb96a3673eeccc Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 10 Feb 2025 22:17:49 +0000 Subject: [PATCH 309/561] remove cxx03 test, fully unblocking c++1X development (#1903) * remove cxx03 test, fully unblocking c++1X development * remove unnecessary macros * pre-commit * remove opt-in analyzer warnings from clang-tidy * revert some changes, flush streams * replace abort with exit(1) to call atexit and dtors * remove more endl and put in explicit flush --- .github/workflows/clang-tidy.yml | 2 +- include/benchmark/benchmark.h | 219 ++++----------------- src/benchmark.cc | 10 +- src/benchmark_register.cc | 2 +- src/check.h | 4 +- src/log.h | 12 -- src/sysinfo.cc | 6 +- src/timers.cc | 3 +- test/BUILD | 17 -- test/CMakeLists.txt | 30 +-- test/benchmark_min_time_flag_iters_test.cc | 4 +- test/benchmark_min_time_flag_time_test.cc | 6 +- test/cxx03_test.cc | 62 ------ test/diagnostics_test.cc | 2 +- test/filter_test.cc | 6 +- test/output_test.h | 6 +- test/output_test_helper.cc | 5 +- 17 files changed, 69 insertions(+), 327 deletions(-) delete mode 100644 test/cxx03_test.cc diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 37a61cdb3a..6d50543bdc 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -35,4 +35,4 @@ jobs: - name: run shell: bash working-directory: ${{ runner.workspace }}/_build - run: run-clang-tidy -checks=*,-clang-analyzer-deadcode* + run: run-clang-tidy -checks=*,-clang-analyzer-deadcode*,-clang-analyzer-optin* diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 86f9dbbabb..4ea085adff 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -163,60 +163,31 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #ifndef BENCHMARK_BENCHMARK_H_ #define BENCHMARK_BENCHMARK_H_ -// The _MSVC_LANG check should detect Visual Studio 2015 Update 3 and newer. -#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) -#define BENCHMARK_HAS_CXX11 -#endif - -// This _MSC_VER check should detect VS 2017 v15.3 and newer. -#if __cplusplus >= 201703L || \ - (defined(_MSC_VER) && _MSC_VER >= 1911 && _MSVC_LANG >= 201703L) -#define BENCHMARK_HAS_CXX17 -#endif - #include #include +#include #include #include +#include #include #include #include #include #include +#include #include #include #include "benchmark/export.h" -#if defined(BENCHMARK_HAS_CXX11) -#include -#include -#include -#include -#endif - #if defined(_MSC_VER) #include // for _ReadWriteBarrier #endif -#ifndef BENCHMARK_HAS_CXX11 -#define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - TypeName& operator=(const TypeName&) -#else #define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete -#endif - -#ifdef BENCHMARK_HAS_CXX17 -#define BENCHMARK_UNUSED [[maybe_unused]] -#elif defined(__GNUC__) || defined(__clang__) -#define BENCHMARK_UNUSED __attribute__((unused)) -#else -#define BENCHMARK_UNUSED -#endif // Used to annotate functions, methods and classes so they // are not optimized by the compiler. Useful for tests @@ -284,12 +255,6 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #define BENCHMARK_UNREACHABLE() ((void)0) #endif -#ifdef BENCHMARK_HAS_CXX11 -#define BENCHMARK_OVERRIDE override -#else -#define BENCHMARK_OVERRIDE -#endif - #if defined(__GNUC__) // Determine the cacheline size based on architecture #if defined(__i386__) || defined(__x86_64__) @@ -495,7 +460,7 @@ BENCHMARK_EXPORT Benchmark* RegisterBenchmarkInternal(Benchmark*); // Ensure that the standard streams are properly initialized in every TU. BENCHMARK_EXPORT int InitializeStreams(); -BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); +[[maybe_unused]] static int stream_init_anchor = InitializeStreams(); } // namespace internal @@ -506,11 +471,9 @@ BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); // Force the compiler to flush pending writes to global memory. Acts as an // effective read/write barrier -#ifdef BENCHMARK_HAS_CXX11 inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { std::atomic_signal_fence(std::memory_order_acq_rel); } -#endif // The DoNotOptimize(...) function can be used to prevent a value or // expression from being optimized away by the compiler. This function is @@ -535,7 +498,6 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { #endif } -#ifdef BENCHMARK_HAS_CXX11 template inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { #if defined(__clang__) @@ -544,8 +506,8 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { asm volatile("" : "+m,r"(value) : : "memory"); #endif } -#endif -#elif defined(BENCHMARK_HAS_CXX11) && (__GNUC__ >= 5) +// !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) +#elif (__GNUC__ >= 5) // Workaround for a bug with full argument copy overhead with GCC. // See: #1340 and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105519 template @@ -601,37 +563,9 @@ inline BENCHMARK_ALWAYS_INLINE DoNotOptimize(Tp&& value) { asm volatile("" : "+m"(value) : : "memory"); } - -#else -// Fallback for GCC < 5. Can add some overhead because the compiler is forced -// to use memory operations instead of operations with registers. -// TODO: Remove if GCC < 5 will be unsupported. -template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { - asm volatile("" : : "m"(value) : "memory"); -} - -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { - asm volatile("" : "+m"(value) : : "memory"); -} - -#ifdef BENCHMARK_HAS_CXX11 -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { - asm volatile("" : "+m"(value) : : "memory"); -} -#endif +// !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) #endif -#ifndef BENCHMARK_HAS_CXX11 -inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { - asm volatile("" : : : "memory"); -} -#endif #elif defined(_MSC_VER) template BENCHMARK_DEPRECATED_MSG( @@ -642,29 +576,11 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { _ReadWriteBarrier(); } -#ifndef BENCHMARK_HAS_CXX11 -inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { _ReadWriteBarrier(); } -#endif #else -#ifdef BENCHMARK_HAS_CXX11 template inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { internal::UseCharPointer(&reinterpret_cast(value)); } -#else -template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { - internal::UseCharPointer(&reinterpret_cast(value)); -} - -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { - internal::UseCharPointer(&reinterpret_cast(value)); -} -#endif // FIXME Add ClobberMemory() for non-gnu and non-msvc compilers, before C++11. #endif @@ -764,12 +680,7 @@ class ThreadTimer; class ThreadManager; class PerfCountersMeasurement; -enum AggregationReportMode -#if defined(BENCHMARK_HAS_CXX11) - : unsigned -#else -#endif -{ +enum AggregationReportMode : unsigned { // The mode has not been manually specified ARM_Unspecified = 0, // The mode is user-specified. @@ -784,11 +695,7 @@ enum AggregationReportMode ARM_FileReportAggregatesOnly | ARM_DisplayReportAggregatesOnly }; -enum Skipped -#if defined(BENCHMARK_HAS_CXX11) - : unsigned -#endif -{ +enum Skipped : unsigned { NotSkipped = 0, SkippedWithMessage, SkippedWithError @@ -1109,7 +1016,7 @@ inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n, } struct State::StateIterator { - struct BENCHMARK_UNUSED Value {}; + struct [[maybe_unused]] Value {}; typedef std::forward_iterator_tag iterator_category; typedef Value value_type; typedef Value reference; @@ -1404,17 +1311,7 @@ class BENCHMARK_EXPORT Benchmark { callback_function setup_; callback_function teardown_; - Benchmark(Benchmark const&) -#if defined(BENCHMARK_HAS_CXX11) - = delete -#endif - ; - - Benchmark& operator=(Benchmark const&) -#if defined(BENCHMARK_HAS_CXX11) - = delete -#endif - ; + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(Benchmark); }; } // namespace internal @@ -1426,10 +1323,8 @@ class BENCHMARK_EXPORT Benchmark { internal::Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn); -#if defined(BENCHMARK_HAS_CXX11) template internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn); -#endif // Remove all registered benchmarks. All pointers to previously registered // benchmarks are invalidated. @@ -1443,17 +1338,16 @@ class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark { FunctionBenchmark(const std::string& name, Function* func) : Benchmark(name), func_(func) {} - void Run(State& st) BENCHMARK_OVERRIDE; + void Run(State& st) override; private: Function* func_; }; -#ifdef BENCHMARK_HAS_CXX11 template class LambdaBenchmark : public Benchmark { public: - void Run(State& st) BENCHMARK_OVERRIDE { lambda_(st); } + void Run(State& st) override { lambda_(st); } private: template @@ -1467,7 +1361,6 @@ class LambdaBenchmark : public Benchmark { Lambda lambda_; }; -#endif } // namespace internal inline internal::Benchmark* RegisterBenchmark(const std::string& name, @@ -1478,7 +1371,6 @@ inline internal::Benchmark* RegisterBenchmark(const std::string& name, ::new internal::FunctionBenchmark(name, fn)); } -#ifdef BENCHMARK_HAS_CXX11 template internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { using BenchType = @@ -1488,10 +1380,8 @@ internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { return internal::RegisterBenchmarkInternal( ::new BenchType(name, std::forward(fn))); } -#endif -#if defined(BENCHMARK_HAS_CXX11) && \ - (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) +#if (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) template internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn, Args&&... args) { @@ -1507,7 +1397,7 @@ class Fixture : public internal::Benchmark { public: Fixture() : internal::Benchmark("") {} - void Run(State& st) BENCHMARK_OVERRIDE { + void Run(State& st) override { this->SetUp(st); this->BenchmarkCase(st); this->TearDown(st); @@ -1538,14 +1428,9 @@ class Fixture : public internal::Benchmark { #endif // Helpers for generating unique variable names -#ifdef BENCHMARK_HAS_CXX11 #define BENCHMARK_PRIVATE_NAME(...) \ BENCHMARK_PRIVATE_CONCAT(benchmark_uniq_, BENCHMARK_PRIVATE_UNIQUE_ID, \ __VA_ARGS__) -#else -#define BENCHMARK_PRIVATE_NAME(n) \ - BENCHMARK_PRIVATE_CONCAT(benchmark_uniq_, BENCHMARK_PRIVATE_UNIQUE_ID, n) -#endif // BENCHMARK_HAS_CXX11 #define BENCHMARK_PRIVATE_CONCAT(a, b, c) BENCHMARK_PRIVATE_CONCAT2(a, b, c) #define BENCHMARK_PRIVATE_CONCAT2(a, b, c) a##b##c @@ -1556,20 +1441,13 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_PRIVATE_DECLARE(n) \ /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ static ::benchmark::internal::Benchmark* BENCHMARK_PRIVATE_NAME(n) \ - BENCHMARK_UNUSED + [[maybe_unused]] -#ifdef BENCHMARK_HAS_CXX11 #define BENCHMARK(...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ new ::benchmark::internal::FunctionBenchmark(#__VA_ARGS__, \ __VA_ARGS__))) -#else -#define BENCHMARK(n) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - new ::benchmark::internal::FunctionBenchmark(#n, n))) -#endif // BENCHMARK_HAS_CXX11 // Old-style macros #define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) @@ -1579,8 +1457,6 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ BENCHMARK(n)->RangePair({{(l1), (h1)}, {(l2), (h2)}}) -#ifdef BENCHMARK_HAS_CXX11 - // Register a benchmark which invokes the function specified by `func` // with the additional arguments specified by `...`. // @@ -1599,8 +1475,6 @@ class Fixture : public internal::Benchmark { #func "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) -#endif // BENCHMARK_HAS_CXX11 - // This will register a benchmark for a templatized function. For example: // // template @@ -1620,17 +1494,12 @@ class Fixture : public internal::Benchmark { new ::benchmark::internal::FunctionBenchmark(#n "<" #a "," #b ">", \ n))) -#ifdef BENCHMARK_HAS_CXX11 #define BENCHMARK_TEMPLATE(n, ...) \ BENCHMARK_PRIVATE_DECLARE(n) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ new ::benchmark::internal::FunctionBenchmark( \ #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) -#else -#define BENCHMARK_TEMPLATE(n, a) BENCHMARK_TEMPLATE1(n, a) -#endif -#ifdef BENCHMARK_HAS_CXX11 // This will register a benchmark for a templatized function, // with the additional arguments specified by `...`. // @@ -1653,17 +1522,16 @@ class Fixture : public internal::Benchmark { #func "<" #a "," #b ">" \ "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) -#endif // BENCHMARK_HAS_CXX11 - -#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ - class BaseClass##_##Method##_Benchmark : public BaseClass { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "/" #Method); \ - } \ - \ - protected: \ - void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ + +#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) override; \ }; #define BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ @@ -1674,7 +1542,7 @@ class Fixture : public internal::Benchmark { } \ \ protected: \ - void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ + void BenchmarkCase(::benchmark::State&) override; \ }; #define BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ @@ -1685,10 +1553,9 @@ class Fixture : public internal::Benchmark { } \ \ protected: \ - void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ + void BenchmarkCase(::benchmark::State&) override; \ }; -#ifdef BENCHMARK_HAS_CXX11 #define BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, ...) \ class BaseClass##_##Method##_Benchmark : public BaseClass<__VA_ARGS__> { \ public: \ @@ -1697,12 +1564,8 @@ class Fixture : public internal::Benchmark { } \ \ protected: \ - void BenchmarkCase(::benchmark::State&) BENCHMARK_OVERRIDE; \ + void BenchmarkCase(::benchmark::State&) override; \ }; -#else -#define BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(n, a) \ - BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(n, a) -#endif #define BENCHMARK_DEFINE_F(BaseClass, Method) \ BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ @@ -1716,14 +1579,9 @@ class Fixture : public internal::Benchmark { BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase -#ifdef BENCHMARK_HAS_CXX11 #define BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, ...) \ BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase -#else -#define BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, a) \ - BENCHMARK_TEMPLATE1_DEFINE_F(BaseClass, Method, a) -#endif #define BENCHMARK_REGISTER_F(BaseClass, Method) \ BENCHMARK_PRIVATE_REGISTER_F(BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)) @@ -1748,15 +1606,10 @@ class Fixture : public internal::Benchmark { BENCHMARK_REGISTER_F(BaseClass, Method); \ void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase -#ifdef BENCHMARK_HAS_CXX11 #define BENCHMARK_TEMPLATE_F(BaseClass, Method, ...) \ BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ BENCHMARK_REGISTER_F(BaseClass, Method); \ void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase -#else -#define BENCHMARK_TEMPLATE_F(BaseClass, Method, a) \ - BENCHMARK_TEMPLATE1_F(BaseClass, Method, a) -#endif // Helper macro to create a main routine in a test that runs the benchmarks // Note the workaround for Hexagon simulator passing argc != 0, argv = NULL. @@ -2016,8 +1869,8 @@ class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter { explicit ConsoleReporter(OutputOptions opts_ = OO_Defaults) : output_options_(opts_), name_field_width_(0), printed_header_(false) {} - bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; - void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; + bool ReportContext(const Context& context) override; + void ReportRuns(const std::vector& reports) override; protected: virtual void PrintRunData(const Run& report); @@ -2032,9 +1885,9 @@ class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter { class BENCHMARK_EXPORT JSONReporter : public BenchmarkReporter { public: JSONReporter() : first_report_(true) {} - bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; - void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; - void Finalize() BENCHMARK_OVERRIDE; + bool ReportContext(const Context& context) override; + void ReportRuns(const std::vector& reports) override; + void Finalize() override; private: void PrintRunData(const Run& report); @@ -2047,8 +1900,8 @@ class BENCHMARK_EXPORT BENCHMARK_DEPRECATED_MSG( : public BenchmarkReporter { public: CSVReporter() : printed_header_(false) {} - bool ReportContext(const Context& context) BENCHMARK_OVERRIDE; - void ReportRuns(const std::vector& reports) BENCHMARK_OVERRIDE; + bool ReportContext(const Context& context) override; + void ReportRuns(const std::vector& reports) override; private: void PrintRunData(const Run& report); diff --git a/src/benchmark.cc b/src/benchmark.cc index 0ea90aeb6a..a900fb471c 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -506,6 +506,7 @@ std::unique_ptr CreateReporter( return PtrType(new CSVReporter()); } std::cerr << "Unexpected format: '" << name << "'\n"; + std::flush(std::cerr); std::exit(1); } @@ -595,8 +596,7 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, std::string const& fname = FLAGS_benchmark_out; if (fname.empty() && file_reporter) { Err << "A custom file reporter was provided but " - "--benchmark_out= was not specified." - << std::endl; + "--benchmark_out= was not specified.\n"; Out.flush(); Err.flush(); std::exit(1); @@ -604,7 +604,7 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, if (!fname.empty()) { output_file.open(fname); if (!output_file.is_open()) { - Err << "invalid file name: '" << fname << "'" << std::endl; + Err << "invalid file name: '" << fname << "'\n"; Out.flush(); Err.flush(); std::exit(1); @@ -691,7 +691,9 @@ void (*HelperPrintf)(); void PrintUsageAndExit() { HelperPrintf(); - exit(0); + std::flush(std::cout); + std::flush(std::cerr); + std::exit(0); } void SetDefaultTimeUnitFromFlag(const std::string& time_unit_flag) { diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 8ade048225..f90df55024 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -125,7 +125,7 @@ bool BenchmarkFamilies::FindBenchmarks( is_negative_filter = true; } if (!re.Init(spec, &error_msg)) { - Err << "Could not compile benchmark re: " << error_msg << std::endl; + Err << "Could not compile benchmark re: " << error_msg << '\n'; return false; } diff --git a/src/check.h b/src/check.h index c1cd5e85e4..f9f223f2a1 100644 --- a/src/check.h +++ b/src/check.h @@ -36,6 +36,8 @@ AbortHandlerT*& GetAbortHandler(); BENCHMARK_NORETURN inline void CallAbortHandler() { GetAbortHandler()(); + std::flush(std::cout); + std::flush(std::cerr); std::abort(); // fallback to enforce noreturn } @@ -57,7 +59,7 @@ class CheckHandler { #pragma warning(disable : 4722) #endif BENCHMARK_NORETURN ~CheckHandler() BENCHMARK_NOEXCEPT_OP(false) { - log_ << std::endl; + log_ << '\n'; CallAbortHandler(); } #if defined(COMPILER_MSVC) diff --git a/src/log.h b/src/log.h index 9a21400b09..57b7bdfc45 100644 --- a/src/log.h +++ b/src/log.h @@ -4,13 +4,6 @@ #include #include -// NOTE: this is also defined in benchmark.h but we're trying to avoid a -// dependency. -// The _MSVC_LANG check should detect Visual Studio 2015 Update 3 and newer. -#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) -#define BENCHMARK_HAS_CXX11 -#endif - namespace benchmark { namespace internal { @@ -31,13 +24,8 @@ class LogType { // NOTE: we could use BENCHMARK_DISALLOW_COPY_AND_ASSIGN but we shouldn't have // a dependency on benchmark.h from here. -#ifndef BENCHMARK_HAS_CXX11 - LogType(const LogType&); - LogType& operator=(const LogType&); -#else LogType(const LogType&) = delete; LogType& operator=(const LogType&) = delete; -#endif }; template diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 2b8252032b..b1926ebe84 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -84,7 +84,7 @@ namespace benchmark { namespace { -void PrintImp(std::ostream& out) { out << std::endl; } +void PrintImp(std::ostream& out) { out << '\n'; } template void PrintImp(std::ostream& out, First&& f, Rest&&... rest) { @@ -95,6 +95,7 @@ void PrintImp(std::ostream& out, First&& f, Rest&&... rest) { template BENCHMARK_NORETURN void PrintErrorAndDie(Args&&... args) { PrintImp(std::cerr, std::forward(args)...); + std::cerr << std::flush; std::exit(EXIT_FAILURE); } @@ -540,8 +541,7 @@ class ThreadAffinityGuard final { ThreadAffinityGuard() : reset_affinity(SetAffinity()) { if (!reset_affinity) std::cerr << "***WARNING*** Failed to set thread affinity. Estimated CPU " - "frequency may be incorrect." - << std::endl; + "frequency may be incorrect.\n"; } ~ThreadAffinityGuard() { diff --git a/src/timers.cc b/src/timers.cc index 7ba540b88b..a947fcf779 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -108,7 +108,8 @@ double MakeTime(struct timespec const& ts) { #endif BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) { - std::cerr << "ERROR: " << msg << std::endl; + std::cerr << "ERROR: " << msg << '\n'; + std::flush(std::cerr); std::exit(EXIT_FAILURE); } diff --git a/test/BUILD b/test/BUILD index c1ca86b5b2..c31810826d 100644 --- a/test/BUILD +++ b/test/BUILD @@ -98,28 +98,11 @@ cc_library( ["*_test.cc"], exclude = [ "*_assembly_test.cc", - "cxx03_test.cc", "link_main_test.cc", ], ) ] -cc_test( - name = "cxx03_test", - size = "small", - srcs = ["cxx03_test.cc"], - copts = TEST_COPTS + ["-std=c++03"], - target_compatible_with = select({ - "//:windows": ["@platforms//:incompatible"], - "//conditions:default": [], - }), - deps = [ - ":output_test_helper", - "//:benchmark", - "//:benchmark_internal_headers", - ], -) - cc_test( name = "link_main_test", size = "small", diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3e2c651830..3686e7ee5f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -# Enable the tests +#Enable the tests set(THREADS_PREFER_PTHREAD_FLAG ON) @@ -198,32 +198,6 @@ benchmark_add_test(NAME profiler_manager_test COMMAND profiler_manager_test --be compile_benchmark_test(profiler_manager_iterations_test) benchmark_add_test(NAME profiler_manager_iterations COMMAND profiler_manager_iterations_test) -# MSVC does not allow to set the language standard to C++98/03. -if(NOT (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) - compile_benchmark_test(cxx03_test) - set_target_properties(cxx03_test - PROPERTIES - CXX_STANDARD 98 - CXX_STANDARD_REQUIRED YES) - # libstdc++ provides different definitions within between dialects. When - # LTO is enabled and -Werror is specified GCC diagnoses this ODR violation - # causing the test to fail to compile. To prevent this we explicitly disable - # the warning. - check_cxx_compiler_flag(-Wno-odr BENCHMARK_HAS_WNO_ODR) - check_cxx_compiler_flag(-Wno-lto-type-mismatch BENCHMARK_HAS_WNO_LTO_TYPE_MISMATCH) - # Cannot set_target_properties multiple times here because the warnings will - # be overwritten on each call - set (DISABLE_LTO_WARNINGS "") - if (BENCHMARK_HAS_WNO_ODR) - set(DISABLE_LTO_WARNINGS "${DISABLE_LTO_WARNINGS} -Wno-odr") - endif() - if (BENCHMARK_HAS_WNO_LTO_TYPE_MISMATCH) - set(DISABLE_LTO_WARNINGS "${DISABLE_LTO_WARNINGS} -Wno-lto-type-mismatch") - endif() - set_target_properties(cxx03_test PROPERTIES LINK_FLAGS "${DISABLE_LTO_WARNINGS}") - benchmark_add_test(NAME cxx03 COMMAND cxx03_test --benchmark_min_time=0.01s) -endif() - compile_output_test(complexity_test) benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=1000000x) @@ -299,7 +273,7 @@ if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage") COMMAND ${LCOV} -q -a before.lcov -a after.lcov --output-file final.lcov COMMAND ${LCOV} -q -r final.lcov "'${CMAKE_SOURCE_DIR}/test/*'" -o final.lcov COMMAND ${GENHTML} final.lcov -o lcov --demangle-cpp --sort -p "${CMAKE_BINARY_DIR}" -t benchmark - DEPENDS filter_test benchmark_test options_test basic_test fixture_test cxx03_test complexity_test + DEPENDS filter_test benchmark_test options_test basic_test fixture_test complexity_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Running LCOV" ) diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index 3de93a7505..4bb79730ae 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -13,11 +13,11 @@ namespace { class TestReporter : public benchmark::ConsoleReporter { public: - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + virtual bool ReportContext(const Context& context) override { return ConsoleReporter::ReportContext(context); }; - virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + virtual void ReportRuns(const std::vector& report) override { assert(report.size() == 1); iter_nums_.push_back(report[0].iterations); ConsoleReporter::ReportRuns(report); diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index 04a82eb95b..47e58a189a 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -19,17 +19,17 @@ typedef int64_t IterationCount; class TestReporter : public benchmark::ConsoleReporter { public: - virtual bool ReportContext(const Context& context) BENCHMARK_OVERRIDE { + virtual bool ReportContext(const Context& context) override { return ConsoleReporter::ReportContext(context); }; - virtual void ReportRuns(const std::vector& report) BENCHMARK_OVERRIDE { + virtual void ReportRuns(const std::vector& report) override { assert(report.size() == 1); ConsoleReporter::ReportRuns(report); }; virtual void ReportRunsConfig(double min_time, bool /* has_explicit_iters */, - IterationCount /* iters */) BENCHMARK_OVERRIDE { + IterationCount /* iters */) override { min_times_.push_back(min_time); } diff --git a/test/cxx03_test.cc b/test/cxx03_test.cc deleted file mode 100644 index 9711c1bd4a..0000000000 --- a/test/cxx03_test.cc +++ /dev/null @@ -1,62 +0,0 @@ -#undef NDEBUG -#include -#include - -#include "benchmark/benchmark.h" - -#if __cplusplus >= 201103L -#error C++11 or greater detected. Should be C++03. -#endif - -#ifdef BENCHMARK_HAS_CXX11 -#error C++11 or greater detected by the library. BENCHMARK_HAS_CXX11 is defined. -#endif - -void BM_empty(benchmark::State& state) { - while (state.KeepRunning()) { - volatile benchmark::IterationCount x = state.iterations(); - ((void)x); - } -} -BENCHMARK(BM_empty); - -// The new C++11 interface for args/ranges requires initializer list support. -// Therefore we provide the old interface to support C++03. -void BM_old_arg_range_interface(benchmark::State& state) { - assert((state.range(0) == 1 && state.range(1) == 2) || - (state.range(0) == 5 && state.range(1) == 6)); - while (state.KeepRunning()) { - } -} -BENCHMARK(BM_old_arg_range_interface)->ArgPair(1, 2)->RangePair(5, 5, 6, 6); - -template -void BM_template2(benchmark::State& state) { - BM_empty(state); -} -BENCHMARK_TEMPLATE2(BM_template2, int, long); - -template -void BM_template1(benchmark::State& state) { - BM_empty(state); -} -BENCHMARK_TEMPLATE(BM_template1, long); -BENCHMARK_TEMPLATE1(BM_template1, int); - -template -struct BM_Fixture : public ::benchmark::Fixture {}; - -BENCHMARK_TEMPLATE_F(BM_Fixture, BM_template1, long)(benchmark::State& state) { - BM_empty(state); -} -BENCHMARK_TEMPLATE1_F(BM_Fixture, BM_template2, int)(benchmark::State& state) { - BM_empty(state); -} - -void BM_counters(benchmark::State& state) { - BM_empty(state); - state.counters["Foo"] = 2; -} -BENCHMARK(BM_counters); - -BENCHMARK_MAIN(); diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index 7c68a98929..2a7f887de3 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -80,7 +80,7 @@ int main(int argc, char* argv[]) { // This test is exercising functionality for debug builds, which are not // available in release builds. Skip the test if we are in that environment // to avoid a test failure. - std::cout << "Diagnostic test disabled in release build" << std::endl; + std::cout << "Diagnostic test disabled in release build\n"; (void)argc; (void)argv; #else diff --git a/test/filter_test.cc b/test/filter_test.cc index 4c8b8ea488..d2d4d96ebd 100644 --- a/test/filter_test.cc +++ b/test/filter_test.cc @@ -90,7 +90,7 @@ int main(int argc, char** argv) { if (returned_count != expected_return) { std::cerr << "ERROR: Expected " << expected_return << " tests to match the filter but returned_count = " - << returned_count << std::endl; + << returned_count << '\n'; return -1; } @@ -99,7 +99,7 @@ int main(int argc, char** argv) { if (reports_count != expected_reports) { std::cerr << "ERROR: Expected " << expected_reports << " tests to be run but reported_count = " << reports_count - << std::endl; + << '\n'; return -1; } @@ -108,7 +108,7 @@ int main(int argc, char** argv) { if (num_families != expected_reports) { std::cerr << "ERROR: Expected " << expected_reports << " test families to be run but num_families = " - << num_families << std::endl; + << num_families << '\n'; return -1; } } diff --git a/test/output_test.h b/test/output_test.h index c08fe1d87e..c48cd20463 100644 --- a/test/output_test.h +++ b/test/output_test.h @@ -21,7 +21,7 @@ #define SET_SUBSTITUTIONS(...) \ int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__) -enum MatchRules { +enum MatchRules : uint8_t { MR_Default, // Skip non-matching lines until a match is found. MR_Next, // Match must occur on the next line. MR_Not // No line between the current position and the next match matches @@ -37,7 +37,7 @@ struct TestCase { std::shared_ptr regex; }; -enum TestCaseID { +enum TestCaseID : uint8_t { TC_ConsoleOut, TC_ConsoleErr, TC_JSONOut, @@ -101,7 +101,7 @@ struct Results { double NumIterations() const; - typedef enum { kCpuTime, kRealTime } BenchmarkTime; + typedef enum : uint8_t { kCpuTime, kRealTime } BenchmarkTime; // get cpu_time or real_time in seconds double GetTime(BenchmarkTime which) const; diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index 265f28aae7..b7c3c510ae 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -490,8 +490,9 @@ static std::string GetTempFileName() { std::string name = GetRandomFileName(); if (!FileExists(name)) return name; } - std::cerr << "Failed to create unique temporary file name" << std::endl; - std::abort(); + std::cerr << "Failed to create unique temporary file name\n"; + std::flush(std::cerr); + std::exit(1); } std::string GetFileReporterOutput(int argc, char* argv[]) { From a125fb6736249462365107a7384eb9d143033e9a Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 11 Feb 2025 00:32:38 +0000 Subject: [PATCH 310/561] run clang-tidy using a common config and reduced set of tests (#1923) * move clang-tidy config somewhere central and reduce it --- .clang-tidy | 39 +++++++++++++++++-- .../{clang-tidy.yml => clang-tidy-lint.yml} | 8 ++-- 2 files changed, 39 insertions(+), 8 deletions(-) rename .github/workflows/{clang-tidy.yml => clang-tidy-lint.yml} (73%) diff --git a/.clang-tidy b/.clang-tidy index 1e229e582e..d6cd768f6d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,37 @@ --- -Checks: 'clang-analyzer-*,readability-redundant-*,performance-*' -WarningsAsErrors: 'clang-analyzer-*,readability-redundant-*,performance-*' -HeaderFilterRegex: '.*' +Checks: > + abseil-*, + bugprone-*, + clang-analyzer-*, + cppcoreguidelines-*, + google-*, + misc-*, + performance-*, + readability-*, + -clang-analyzer-deadcode*, + -clang-analyzer-optin*, + -readability-identifier-length +WarningsAsErrors: '' +HeaderFilterRegex: '' FormatStyle: none -User: user +CheckOptions: + llvm-else-after-return.WarnOnConditionVariables: 'false' + modernize-loop-convert.MinConfidence: reasonable + modernize-replace-auto-ptr.IncludeStyle: llvm + cert-str34-c.DiagnoseSignedUnsignedCharComparisons: 'false' + google-readability-namespace-comments.ShortNamespaceLines: '10' + cert-err33-c.CheckedFunctions: '::aligned_alloc;::asctime_s;::at_quick_exit;::atexit;::bsearch;::bsearch_s;::btowc;::c16rtomb;::c32rtomb;::calloc;::clock;::cnd_broadcast;::cnd_init;::cnd_signal;::cnd_timedwait;::cnd_wait;::ctime_s;::fclose;::fflush;::fgetc;::fgetpos;::fgets;::fgetwc;::fopen;::fopen_s;::fprintf;::fprintf_s;::fputc;::fputs;::fputwc;::fputws;::fread;::freopen;::freopen_s;::fscanf;::fscanf_s;::fseek;::fsetpos;::ftell;::fwprintf;::fwprintf_s;::fwrite;::fwscanf;::fwscanf_s;::getc;::getchar;::getenv;::getenv_s;::gets_s;::getwc;::getwchar;::gmtime;::gmtime_s;::localtime;::localtime_s;::malloc;::mbrtoc16;::mbrtoc32;::mbsrtowcs;::mbsrtowcs_s;::mbstowcs;::mbstowcs_s;::memchr;::mktime;::mtx_init;::mtx_lock;::mtx_timedlock;::mtx_trylock;::mtx_unlock;::printf_s;::putc;::putwc;::raise;::realloc;::remove;::rename;::scanf;::scanf_s;::setlocale;::setvbuf;::signal;::snprintf;::snprintf_s;::sprintf;::sprintf_s;::sscanf;::sscanf_s;::strchr;::strerror_s;::strftime;::strpbrk;::strrchr;::strstr;::strtod;::strtof;::strtoimax;::strtok;::strtok_s;::strtol;::strtold;::strtoll;::strtoul;::strtoull;::strtoumax;::strxfrm;::swprintf;::swprintf_s;::swscanf;::swscanf_s;::thrd_create;::thrd_detach;::thrd_join;::thrd_sleep;::time;::timespec_get;::tmpfile;::tmpfile_s;::tmpnam;::tmpnam_s;::tss_create;::tss_get;::tss_set;::ungetc;::ungetwc;::vfprintf;::vfprintf_s;::vfscanf;::vfscanf_s;::vfwprintf;::vfwprintf_s;::vfwscanf;::vfwscanf_s;::vprintf_s;::vscanf;::vscanf_s;::vsnprintf;::vsnprintf_s;::vsprintf;::vsprintf_s;::vsscanf;::vsscanf_s;::vswprintf;::vswprintf_s;::vswscanf;::vswscanf_s;::vwprintf_s;::vwscanf;::vwscanf_s;::wcrtomb;::wcschr;::wcsftime;::wcspbrk;::wcsrchr;::wcsrtombs;::wcsrtombs_s;::wcsstr;::wcstod;::wcstof;::wcstoimax;::wcstok;::wcstok_s;::wcstol;::wcstold;::wcstoll;::wcstombs;::wcstombs_s;::wcstoul;::wcstoull;::wcstoumax;::wcsxfrm;::wctob;::wctrans;::wctype;::wmemchr;::wprintf_s;::wscanf;::wscanf_s;' + cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: 'false' + cert-dcl16-c.NewSuffixes: 'L;LL;LU;LLU' + google-readability-braces-around-statements.ShortStatementLines: '1' + cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: 'true' + google-readability-namespace-comments.SpacesBeforeComments: '2' + modernize-loop-convert.MaxCopySize: '16' + modernize-pass-by-value.IncludeStyle: llvm + modernize-use-nullptr.NullMacros: 'NULL' + llvm-qualified-auto.AddConstToQualified: 'false' + modernize-loop-convert.NamingStyle: CamelCase + llvm-else-after-return.WarnOnUnfixable: 'false' + google-readability-function-size.StatementThreshold: '800' +... + diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy-lint.yml similarity index 73% rename from .github/workflows/clang-tidy.yml rename to .github/workflows/clang-tidy-lint.yml index 6d50543bdc..e38153b823 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,11 +17,11 @@ jobs: run: sudo apt update && sudo apt -y install clang-tidy - name: create build environment - run: cmake -E make_directory ${{ runner.workspace }}/_build + run: cmake -E make_directory ${{ github.workspace }}/_build - name: configure cmake shell: bash - working-directory: ${{ runner.workspace }}/_build + working-directory: ${{ github.workspace }}/_build run: > cmake $GITHUB_WORKSPACE -DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF @@ -34,5 +34,5 @@ jobs: - name: run shell: bash - working-directory: ${{ runner.workspace }}/_build - run: run-clang-tidy -checks=*,-clang-analyzer-deadcode*,-clang-analyzer-optin* + working-directory: ${{ github.workspace }}/_build + run: run-clang-tidy -config-file=$GITHUB_WORKSPACE/.clang-tidy From 6a508bf11e4bfc47d07f8b0edd1e25a21a76b6a6 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 10 Feb 2025 17:16:03 -0800 Subject: [PATCH 311/561] benchmark declarations can and should be const (clang-tidy) (#1924) * benchmark declarations can and should be const (clang-tidy) * clang-format * add clang-tidy ignore file to remove googletest (and other third party) source for consideration --- .clang-tidy.ignore | 1 + include/benchmark/benchmark.h | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 .clang-tidy.ignore diff --git a/.clang-tidy.ignore b/.clang-tidy.ignore new file mode 100644 index 0000000000..dba559d6ca --- /dev/null +++ b/.clang-tidy.ignore @@ -0,0 +1 @@ +.*third_party/.* diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 4ea085adff..d2b024a495 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1438,10 +1438,10 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method) \ BaseClass##_##Method##_Benchmark -#define BENCHMARK_PRIVATE_DECLARE(n) \ - /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ - static ::benchmark::internal::Benchmark* BENCHMARK_PRIVATE_NAME(n) \ - [[maybe_unused]] +#define BENCHMARK_PRIVATE_DECLARE(n) \ + /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ + static ::benchmark::internal::Benchmark const* const BENCHMARK_PRIVATE_NAME( \ + n) [[maybe_unused]] #define BENCHMARK(...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ From 05c5930d9636c56a3c55f834ba738c688d4a95cd Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 11 Feb 2025 13:10:34 -0800 Subject: [PATCH 312/561] [clang-tidy] use unique_ptr for benchmark registration (#1927) * use unique_ptr for benchmark registration --- include/benchmark/benchmark.h | 98 +++++++++++++++++------------------ src/benchmark_register.cc | 8 +-- 2 files changed, 51 insertions(+), 55 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index d2b024a495..1357a0ef8d 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -173,6 +173,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #include #include #include +#include #include #include #include @@ -456,7 +457,8 @@ void UseCharPointer(char const volatile*); // Take ownership of the pointer and register the benchmark. Return the // registered benchmark. -BENCHMARK_EXPORT Benchmark* RegisterBenchmarkInternal(Benchmark*); +BENCHMARK_EXPORT Benchmark* RegisterBenchmarkInternal( + std::unique_ptr); // Ensure that the standard streams are properly initialized in every TU. BENCHMARK_EXPORT int InitializeStreams(); @@ -1119,12 +1121,12 @@ class BENCHMARK_EXPORT Benchmark { // Run this benchmark once for a number of values picked from the // ranges [start..limit]. (starts and limits are always picked.) // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... - Benchmark* Ranges(const std::vector >& ranges); + Benchmark* Ranges(const std::vector>& ranges); // Run this benchmark once for each combination of values in the (cartesian) // product of the supplied argument lists. // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... - Benchmark* ArgsProduct(const std::vector >& arglists); + Benchmark* ArgsProduct(const std::vector>& arglists); // Equivalent to ArgNames({name}) Benchmark* ArgName(const std::string& name); @@ -1137,7 +1139,7 @@ class BENCHMARK_EXPORT Benchmark { // NOTE: This is a legacy C++03 interface provided for compatibility only. // New code should use 'Ranges'. Benchmark* RangePair(int64_t lo1, int64_t hi1, int64_t lo2, int64_t hi2) { - std::vector > ranges; + std::vector> ranges; ranges.push_back(std::make_pair(lo1, hi1)); ranges.push_back(std::make_pair(lo2, hi2)); return Ranges(ranges); @@ -1288,8 +1290,8 @@ class BENCHMARK_EXPORT Benchmark { std::string name_; AggregationReportMode aggregation_report_mode_; - std::vector arg_names_; // Args for all benchmark runs - std::vector > args_; // Args for all benchmark runs + std::vector arg_names_; // Args for all benchmark runs + std::vector> args_; // Args for all benchmark runs TimeUnit time_unit_; bool use_default_time_unit_; @@ -1349,36 +1351,28 @@ class LambdaBenchmark : public Benchmark { public: void Run(State& st) override { lambda_(st); } - private: template LambdaBenchmark(const std::string& name, OLambda&& lam) : Benchmark(name), lambda_(std::forward(lam)) {} + private: LambdaBenchmark(LambdaBenchmark const&) = delete; - - template // NOLINTNEXTLINE(readability-redundant-declaration) - friend Benchmark* ::benchmark::RegisterBenchmark(const std::string&, Lam&&); - Lambda lambda_; }; } // namespace internal inline internal::Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn) { - // FIXME: this should be a `std::make_unique<>()` but we don't have C++14. - // codechecker_intentional [cplusplus.NewDeleteLeaks] return internal::RegisterBenchmarkInternal( - ::new internal::FunctionBenchmark(name, fn)); + std::make_unique(name, fn)); } template internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { using BenchType = internal::LambdaBenchmark::type>; - // FIXME: this should be a `std::make_unique<>()` but we don't have C++14. - // codechecker_intentional [cplusplus.NewDeleteLeaks] return internal::RegisterBenchmarkInternal( - ::new BenchType(name, std::forward(fn))); + std::make_unique(name, std::forward(fn))); } #if (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) @@ -1443,11 +1437,11 @@ class Fixture : public internal::Benchmark { static ::benchmark::internal::Benchmark const* const BENCHMARK_PRIVATE_NAME( \ n) [[maybe_unused]] -#define BENCHMARK(...) \ - BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - new ::benchmark::internal::FunctionBenchmark(#__VA_ARGS__, \ - __VA_ARGS__))) +#define BENCHMARK(...) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + std::make_unique<::benchmark::internal::FunctionBenchmark>( \ + #__VA_ARGS__, __VA_ARGS__))) // Old-style macros #define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) @@ -1468,11 +1462,11 @@ class Fixture : public internal::Benchmark { //} // /* Registers a benchmark named "BM_takes_args/int_string_test` */ // BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); -#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ - BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - new ::benchmark::internal::FunctionBenchmark( \ - #func "/" #test_case_name, \ +#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + std::make_unique<::benchmark::internal::FunctionBenchmark>( \ + #func "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) // This will register a benchmark for a templatized function. For example: @@ -1483,21 +1477,22 @@ class Fixture : public internal::Benchmark { // BENCHMARK_TEMPLATE(BM_Foo, 1); // // will register BM_Foo<1> as a benchmark. -#define BENCHMARK_TEMPLATE1(n, a) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - new ::benchmark::internal::FunctionBenchmark(#n "<" #a ">", n))) - -#define BENCHMARK_TEMPLATE2(n, a, b) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - new ::benchmark::internal::FunctionBenchmark(#n "<" #a "," #b ">", \ - n))) - -#define BENCHMARK_TEMPLATE(n, ...) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - new ::benchmark::internal::FunctionBenchmark( \ +#define BENCHMARK_TEMPLATE1(n, a) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + std::make_unique<::benchmark::internal::FunctionBenchmark>( \ + #n "<" #a ">", n))) + +#define BENCHMARK_TEMPLATE2(n, a, b) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + std::make_unique<::benchmark::internal::FunctionBenchmark>( \ + #n "<" #a "," #b ">", n))) + +#define BENCHMARK_TEMPLATE(n, ...) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + std::make_unique<::benchmark::internal::FunctionBenchmark>( \ #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) // This will register a benchmark for a templatized function, @@ -1515,12 +1510,12 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_TEMPLATE1_CAPTURE(func, a, test_case_name, ...) \ BENCHMARK_CAPTURE(func, test_case_name, __VA_ARGS__) -#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ - BENCHMARK_PRIVATE_DECLARE(func) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - new ::benchmark::internal::FunctionBenchmark( \ - #func "<" #a "," #b ">" \ - "/" #test_case_name, \ +#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(func) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + std::make_unique<::benchmark::internal::FunctionBenchmark>( \ + #func "<" #a "," #b ">" \ + "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) #define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ @@ -1586,9 +1581,10 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_REGISTER_F(BaseClass, Method) \ BENCHMARK_PRIVATE_REGISTER_F(BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)) -#define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ - BENCHMARK_PRIVATE_DECLARE(TestName) = \ - (::benchmark::internal::RegisterBenchmarkInternal(new TestName())) +#define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ + BENCHMARK_PRIVATE_DECLARE(TestName) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + std::make_unique())) // This macro will define and register a benchmark within a fixture class. #define BENCHMARK_F(BaseClass, Method) \ diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index f90df55024..682bd4855d 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -185,11 +185,11 @@ bool BenchmarkFamilies::FindBenchmarks( return true; } -Benchmark* RegisterBenchmarkInternal(Benchmark* bench) { - std::unique_ptr bench_ptr(bench); +Benchmark* RegisterBenchmarkInternal(std::unique_ptr bench) { + Benchmark* bench_ptr = bench.get(); BenchmarkFamilies* families = BenchmarkFamilies::GetInstance(); - families->AddBenchmark(std::move(bench_ptr)); - return bench; + families->AddBenchmark(std::move(bench)); + return bench_ptr; } // FIXME: This function is a hack so that benchmark.cc can access From c68e308b4f531d43bed368ee48a4fa2c0fb44ee8 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:15:20 -0800 Subject: [PATCH 313/561] [clang-tidy] fix warning about decaying array to pointer (#1926) * [clang-tidy] fix warning about decaying array to pointer * fix a different warning (old style cast) * use string_view instead of old-style const char* strings * ensure bazel windows is using c++17 * learn to use bazel * and tests * precommit fix * more string_view creation and casting * format * format * [clang-tidy] use unique_ptr for benchmark registration (#1927) * use unique_ptr for benchmark registration --- BUILD.bazel | 6 +++++- include/benchmark/benchmark.h | 2 +- src/check.h | 12 ++++++++---- test/BUILD | 12 ++++++++---- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 95557a35b2..8d91c4df85 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -17,6 +17,10 @@ COPTS = [ "-Werror=old-style-cast", ] +MSVC_COPTS = [ + "/std:c++17", +] + config_setting( name = "windows", constraint_values = ["@platforms//os:windows"], @@ -45,7 +49,7 @@ cc_library( "include/benchmark/export.h", ], copts = select({ - ":windows": [], + ":windows": MSVC_COPTS, "//conditions:default": COPTS, }), defines = [ diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 1357a0ef8d..0b0b6e9aac 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1612,7 +1612,7 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_MAIN() \ int main(int argc, char** argv) { \ char arg0_default[] = "benchmark"; \ - char* args_default = arg0_default; \ + char* args_default = reinterpret_cast(arg0_default); \ if (!argv) { \ argc = 1; \ argv = &args_default; \ diff --git a/src/check.h b/src/check.h index f9f223f2a1..aa8c78c92f 100644 --- a/src/check.h +++ b/src/check.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "benchmark/export.h" #include "internal_macros.h" @@ -46,7 +47,8 @@ BENCHMARK_NORETURN inline void CallAbortHandler() { // destructed. class CheckHandler { public: - CheckHandler(const char* check, const char* file, const char* func, int line) + CheckHandler(std::string_view check, std::string_view file, + std::string_view func, int line) : log_(GetErrorLogInstance()) { log_ << file << ":" << line << ": " << func << ": Check `" << check << "' failed. "; @@ -80,9 +82,11 @@ class CheckHandler { // The BM_CHECK macro returns a std::ostream object that can have extra // information written to it. #ifndef NDEBUG -#define BM_CHECK(b) \ - (b ? ::benchmark::internal::GetNullLogInstance() \ - : ::benchmark::internal::CheckHandler(#b, __FILE__, __func__, __LINE__) \ +#define BM_CHECK(b) \ + (b ? ::benchmark::internal::GetNullLogInstance() \ + : ::benchmark::internal::CheckHandler( \ + std::string_view(#b), std::string_view(__FILE__), \ + std::string_view(__func__), __LINE__) \ .GetLog()) #else #define BM_CHECK(b) ::benchmark::internal::GetNullLogInstance() diff --git a/test/BUILD b/test/BUILD index c31810826d..e3558a94d6 100644 --- a/test/BUILD +++ b/test/BUILD @@ -24,6 +24,10 @@ TEST_COPTS = [ "-Werror=old-style-cast", ] +TEST_MSVC_OPTS = [ + "/std:c++17", +] + # Some of the issues with DoNotOptimize only occur when optimization is enabled PER_SRC_COPTS = { "donotoptimize_test.cc": ["-O3"], @@ -45,7 +49,7 @@ cc_library( srcs = ["output_test_helper.cc"], hdrs = ["output_test.h"], copts = select({ - "//:windows": [], + "//:windows": TEST_MSVC_OPTS, "//conditions:default": TEST_COPTS, }), deps = [ @@ -61,7 +65,7 @@ cc_library( size = "small", srcs = [test_src], copts = select({ - "//:windows": [], + "//:windows": TEST_MSVC_OPTS, "//conditions:default": TEST_COPTS, }) + PER_SRC_COPTS.get(test_src, []), deps = [ @@ -82,7 +86,7 @@ cc_library( srcs = [test_src], args = TEST_ARGS + PER_SRC_TEST_ARGS.get(test_src, []), copts = select({ - "//:windows": [], + "//:windows": TEST_MSVC_OPTS, "//conditions:default": TEST_COPTS, }) + PER_SRC_COPTS.get(test_src, []), deps = [ @@ -108,7 +112,7 @@ cc_test( size = "small", srcs = ["link_main_test.cc"], copts = select({ - "//:windows": [], + "//:windows": TEST_MSVC_OPTS, "//conditions:default": TEST_COPTS, }), deps = ["//:benchmark_main"], From f8db7f6c070bc95b155bafb9a56f3a5615738fe6 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:56:06 -0800 Subject: [PATCH 314/561] [clang-tidy] fix missing braces (#1928) * [clang-tidy] fix missing braces --- src/benchmark.cc | 66 +++++++++---- src/benchmark_register.cc | 16 ++- src/benchmark_runner.cc | 30 ++++-- src/colorprint.cc | 4 +- src/commandlineflags.cc | 47 ++++++--- src/complexity.cc | 4 +- src/console_reporter.cc | 3 +- src/counter.cc | 4 +- src/csv_reporter.cc | 12 ++- src/json_reporter.cc | 17 ++-- src/reporter.cc | 18 +++- src/statistics.cc | 36 +++++-- src/string_util.cc | 19 +++- src/sysinfo.cc | 110 ++++++++++++++------- src/timers.cc | 7 +- test/benchmark_min_time_flag_iters_test.cc | 4 +- test/benchmark_min_time_flag_time_test.cc | 4 +- test/benchmark_test.cc | 28 ++++-- test/diagnostics_test.cc | 16 ++- test/filter_test.cc | 3 +- test/internal_threading_test.cc | 3 +- test/output_test_helper.cc | 67 +++++++++---- test/perf_counters_gtest.cc | 8 +- test/profiler_manager_iterations_test.cc | 4 +- test/register_benchmark_test.cc | 3 +- test/skip_with_error_test.cc | 3 +- test/user_counters_thousands_test.cc | 3 +- 27 files changed, 390 insertions(+), 149 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index a900fb471c..0c14137475 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -280,7 +280,9 @@ void State::SkipWithMessage(const std::string& msg) { } } total_iterations_ = 0; - if (timer_->running()) timer_->StopTimer(); + if (timer_->running()) { + timer_->StopTimer(); + } } void State::SkipWithError(const std::string& msg) { @@ -293,7 +295,9 @@ void State::SkipWithError(const std::string& msg) { } } total_iterations_ = 0; - if (timer_->running()) timer_->StopTimer(); + if (timer_->running()) { + timer_->StopTimer(); + } } void State::SetIterationTime(double seconds) { @@ -309,10 +313,13 @@ void State::StartKeepRunning() { BM_CHECK(!started_ && !finished_); started_ = true; total_iterations_ = skipped() ? 0 : max_iterations; - if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) + if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) { profiler_manager_->AfterSetupStart(); + } manager_->StartStopBarrier(); - if (!skipped()) ResumeTiming(); + if (!skipped()) { + ResumeTiming(); + } } void State::FinishKeepRunning() { @@ -324,8 +331,9 @@ void State::FinishKeepRunning() { total_iterations_ = 0; finished_ = true; manager_->StartStopBarrier(); - if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) + if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) { profiler_manager_->BeforeTeardownStop(); + } } namespace internal { @@ -334,7 +342,9 @@ namespace { // Flushes streams after invoking reporter methods that write to them. This // ensures users get timely updates even when streams are not line-buffered. void FlushStreams(BenchmarkReporter* reporter) { - if (!reporter) return; + if (!reporter) { + return; + } std::flush(reporter->GetOutputStream()); std::flush(reporter->GetErrorStream()); } @@ -347,16 +357,20 @@ void Report(BenchmarkReporter* display_reporter, assert(reporter); // If there are no aggregates, do output non-aggregates. aggregates_only &= !results.aggregates_only.empty(); - if (!aggregates_only) reporter->ReportRuns(results.non_aggregates); - if (!results.aggregates_only.empty()) + if (!aggregates_only) { + reporter->ReportRuns(results.non_aggregates); + } + if (!results.aggregates_only.empty()) { reporter->ReportRuns(results.aggregates_only); + } }; report_one(display_reporter, run_results.display_report_aggregates_only, run_results); - if (file_reporter) + if (file_reporter) { report_one(file_reporter, run_results.file_report_aggregates_only, run_results); + } FlushStreams(display_reporter); FlushStreams(file_reporter); @@ -377,10 +391,13 @@ void RunBenchmarks(const std::vector& benchmarks, std::max(name_field_width, benchmark.name().str().size()); might_have_aggregates |= benchmark.repetitions() > 1; - for (const auto& Stat : benchmark.statistics()) + for (const auto& Stat : benchmark.statistics()) { stat_field_width = std::max(stat_field_width, Stat.name_.size()); + } + } + if (might_have_aggregates) { + name_field_width += 1 + stat_field_width; } - if (might_have_aggregates) name_field_width += 1 + stat_field_width; // Print header here BenchmarkReporter::Context context; @@ -413,15 +430,17 @@ void RunBenchmarks(const std::vector& benchmarks, // Loop through all benchmarks for (const BenchmarkInstance& benchmark : benchmarks) { BenchmarkReporter::PerFamilyRunReports* reports_for_family = nullptr; - if (benchmark.complexity() != oNone) + if (benchmark.complexity() != oNone) { reports_for_family = &per_family_reports[benchmark.family_index()]; + } benchmarks_with_threads += (benchmark.threads() > 1); runners.emplace_back(benchmark, &perfcounters, reports_for_family); int num_repeats_of_this_instance = runners.back().GetNumRepeats(); num_repetitions_total += static_cast(num_repeats_of_this_instance); - if (reports_for_family) + if (reports_for_family) { reports_for_family->num_runs_total += num_repeats_of_this_instance; + } } assert(runners.size() == benchmarks.size() && "Unexpected runner count."); @@ -456,14 +475,17 @@ void RunBenchmarks(const std::vector& benchmarks, for (size_t repetition_index : repetition_indices) { internal::BenchmarkRunner& runner = runners[repetition_index]; runner.DoOneRepetition(); - if (runner.HasRepeatsRemaining()) continue; + if (runner.HasRepeatsRemaining()) { + continue; + } // FIXME: report each repetition separately, not all of them in bulk. display_reporter->ReportRunsConfig( runner.GetMinTime(), runner.HasExplicitIters(), runner.GetIters()); - if (file_reporter) + if (file_reporter) { file_reporter->ReportRunsConfig( runner.GetMinTime(), runner.HasExplicitIters(), runner.GetIters()); + } RunResults run_results = runner.GetResults(); @@ -484,7 +506,9 @@ void RunBenchmarks(const std::vector& benchmarks, } } display_reporter->Finalize(); - if (file_reporter) file_reporter->Finalize(); + if (file_reporter) { + file_reporter->Finalize(); + } FlushStreams(display_reporter); FlushStreams(file_reporter); } @@ -579,8 +603,9 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, BenchmarkReporter* file_reporter, std::string spec) { - if (spec.empty() || spec == "all") + if (spec.empty() || spec == "all") { spec = "."; // Regexp that matches all benchmarks + } // Setup the reporters std::ofstream output_file; @@ -635,8 +660,9 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, } if (FLAGS_benchmark_list_tests) { - for (auto const& benchmark : benchmarks) + for (auto const& benchmark : benchmarks) { Out << benchmark.name().str() << "\n"; + } } else { internal::RunBenchmarks(benchmarks, display_reporter, file_reporter); } @@ -749,7 +775,9 @@ void ParseCommandLineFlags(int* argc, char** argv) { ParseStringFlag(argv[i], "benchmark_time_unit", &FLAGS_benchmark_time_unit) || ParseInt32Flag(argv[i], "v", &FLAGS_v)) { - for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1]; + for (int j = i; j != *argc - 1; ++j) { + argv[j] = argv[j + 1]; + } --(*argc); --i; diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 682bd4855d..23934b0efb 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -140,7 +140,9 @@ bool BenchmarkFamilies::FindBenchmarks( int per_family_instance_index = 0; // Family was deleted or benchmark doesn't match - if (!family) continue; + if (!family) { + continue; + } if (family->ArgsCnt() == -1) { family->Args({}); @@ -159,7 +161,9 @@ bool BenchmarkFamilies::FindBenchmarks( // reserve in the special case the regex ".", since we know the final // family size. this doesn't take into account any disabled benchmarks // so worst case we reserve more than we need. - if (spec == ".") benchmarks->reserve(benchmarks->size() + family_size); + if (spec == ".") { + benchmarks->reserve(benchmarks->size() + family_size); + } for (auto const& args : family->args_) { for (int num_threads : *thread_counts) { @@ -177,7 +181,9 @@ bool BenchmarkFamilies::FindBenchmarks( // Only bump the next family index once we've estabilished that // at least one instance of this family will be run. - if (next_family_index == family_index) ++next_family_index; + if (next_family_index == family_index) { + ++next_family_index; + } } } } @@ -474,7 +480,9 @@ const char* Benchmark::GetName() const { return name_.c_str(); } int Benchmark::ArgsCnt() const { if (args_.empty()) { - if (arg_names_.empty()) return -1; + if (arg_names_.empty()) { + return -1; + } return static_cast(arg_names_.size()); } return static_cast(args_.front().size()); diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 3e8aea7376..388953c131 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -159,17 +159,23 @@ void RunInThread(const BenchmarkInstance* b, IterationCount iters, double ComputeMinTime(const benchmark::internal::BenchmarkInstance& b, const BenchTimeType& iters_or_time) { - if (!IsZero(b.min_time())) return b.min_time(); + if (!IsZero(b.min_time())) { + return b.min_time(); + } // If the flag was used to specify number of iters, then return the default // min_time. - if (iters_or_time.tag == BenchTimeType::ITERS) return kDefaultMinTime; + if (iters_or_time.tag == BenchTimeType::ITERS) { + return kDefaultMinTime; + } return iters_or_time.time; } IterationCount ComputeIters(const benchmark::internal::BenchmarkInstance& b, const BenchTimeType& iters_or_time) { - if (b.iterations() != 0) return b.iterations(); + if (b.iterations() != 0) { + return b.iterations(); + } // We've already concluded that this flag is currently used to pass // iters but do a check here again anyway. @@ -297,7 +303,9 @@ BenchmarkRunner::IterationResults BenchmarkRunner::DoNIterations() { // The main thread has finished. Now let's wait for the other threads. manager->WaitForAllThreads(); - for (std::thread& thread : pool) thread.join(); + for (std::thread& thread : pool) { + thread.join(); + } IterationResults i; // Acquire the measurements/counters from the manager, UNDER THE LOCK! @@ -460,7 +468,9 @@ void BenchmarkRunner::DoOneRepetition() { // this warmup never happened except the fact that warmup_done is set. Every // other manipulation of the BenchmarkRunner instance would be a bug! Please // fix it. - if (!warmup_done) RunWarmUp(); + if (!warmup_done) { + RunWarmUp(); + } IterationResults i; // We *may* be gradually increasing the length (iteration count) @@ -482,8 +492,10 @@ void BenchmarkRunner::DoOneRepetition() { const bool results_are_significant = !is_the_first_repetition || has_explicit_iteration_count || ShouldReportIterationResults(i); - - if (results_are_significant) break; // Good, let's report them! + // Good, let's report them! + if (results_are_significant) { + break; + } // Nope, bad iteration. Let's re-estimate the hopefully-sufficient // iteration count, and run the benchmark again... @@ -518,7 +530,9 @@ void BenchmarkRunner::DoOneRepetition() { if (reports_for_family) { ++reports_for_family->num_runs_done; - if (!report.skipped) reports_for_family->Runs.push_back(report); + if (!report.skipped) { + reports_for_family->Runs.push_back(report); + } } run_results.non_aggregates.push_back(report); diff --git a/src/colorprint.cc b/src/colorprint.cc index fd1971ad3c..e7d7a2d2a8 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -156,7 +156,9 @@ void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, SetConsoleTextAttribute(stdout_handle, original_color_attrs); #else const char* color_code = GetPlatformColorCode(color); - if (color_code) out << FormatString("\033[0;3%sm", color_code); + if (color_code) { + out << FormatString("\033[0;3%sm", color_code); + } out << FormatString(fmt, args) << "\033[m"; #endif } diff --git a/src/commandlineflags.cc b/src/commandlineflags.cc index dcb414959d..5cff92558c 100644 --- a/src/commandlineflags.cc +++ b/src/commandlineflags.cc @@ -113,8 +113,9 @@ static std::string FlagToEnvVar(const char* flag) { const std::string flag_str(flag); std::string env_var; - for (size_t i = 0; i != flag_str.length(); ++i) + for (size_t i = 0; i != flag_str.length(); ++i) { env_var += static_cast(::toupper(flag_str.c_str()[i])); + } return env_var; } @@ -167,7 +168,9 @@ std::map KvPairsFromEnv( const std::string env_var = FlagToEnvVar(flag); const char* const value_str = getenv(env_var.c_str()); - if (value_str == nullptr) return default_val; + if (value_str == nullptr) { + return default_val; + } std::map value; if (!ParseKvPairs("Environment variable " + env_var, value_str, &value)) { @@ -184,23 +187,31 @@ std::map KvPairsFromEnv( const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be nullptr. - if (str == nullptr || flag == nullptr) return nullptr; + if (str == nullptr || flag == nullptr) { + return nullptr; + } // The flag must start with "--". const std::string flag_str = std::string("--") + std::string(flag); const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; + if (strncmp(str, flag_str.c_str(), flag_len) != 0) { + return nullptr; + } // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. - if (def_optional && (flag_end[0] == '\0')) return flag_end; + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. - if (flag_end[0] != '=') return nullptr; + if (flag_end[0] != '=') { + return nullptr; + } // Returns the string after "=". return flag_end + 1; @@ -212,7 +223,9 @@ bool ParseBoolFlag(const char* str, const char* flag, bool* value) { const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. - if (value_str == nullptr) return false; + if (value_str == nullptr) { + return false; + } // Converts the string value to a bool. *value = IsTruthyFlagValue(value_str); @@ -225,7 +238,9 @@ bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == nullptr) return false; + if (value_str == nullptr) { + return false; + } // Sets *value to the value of the flag. return ParseInt32(std::string("The value of flag --") + flag, value_str, @@ -238,7 +253,9 @@ bool ParseDoubleFlag(const char* str, const char* flag, double* value) { const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == nullptr) return false; + if (value_str == nullptr) { + return false; + } // Sets *value to the value of the flag. return ParseDouble(std::string("The value of flag --") + flag, value_str, @@ -251,7 +268,9 @@ bool ParseStringFlag(const char* str, const char* flag, std::string* value) { const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == nullptr) return false; + if (value_str == nullptr) { + return false; + } *value = value_str; return true; @@ -262,11 +281,15 @@ bool ParseKeyValueFlag(const char* str, const char* flag, std::map* value) { const char* const value_str = ParseFlagValue(str, flag, false); - if (value_str == nullptr) return false; + if (value_str == nullptr) { + return false; + } for (const auto& kvpair : StrSplit(value_str, ',')) { const auto kv = StrSplit(kvpair, '='); - if (kv.size() != 2) return false; + if (kv.size() != 2) { + return false; + } value->emplace(kv[0], kv[1]); } diff --git a/src/complexity.cc b/src/complexity.cc index 63acd504d7..a474645a0d 100644 --- a/src/complexity.cc +++ b/src/complexity.cc @@ -157,7 +157,9 @@ std::vector ComputeBigO( typedef BenchmarkReporter::Run Run; std::vector results; - if (reports.size() < 2) return results; + if (reports.size() < 2) { + return results; + } // Accumulators. std::vector n; diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 35c3de2a4d..2cdd995dd8 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -189,8 +189,9 @@ void ConsoleReporter::PrintRunData(const Run& result) { unit = "%"; } else { s = HumanReadableNumber(c.second.value, c.second.oneK); - if (c.second.flags & Counter::kIsRate) + if (c.second.flags & Counter::kIsRate) { unit = (c.second.flags & Counter::kInvert) ? "s" : "/s"; + } } if (output_options_ & OO_Tabular) { printer(Out, COLOR_DEFAULT, " %*s%s", cNameLen - strlen(unit), s.c_str(), diff --git a/src/counter.cc b/src/counter.cc index aa14cd8092..e0d320dcc4 100644 --- a/src/counter.cc +++ b/src/counter.cc @@ -64,7 +64,9 @@ void Increment(UserCounters* l, UserCounters const& r) { } bool SameNames(UserCounters const& l, UserCounters const& r) { - if (&l == &r) return true; + if (&l == &r) { + return true; + } if (l.size() != r.size()) { return false; } diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 4b39e2c52f..82a391ef30 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -66,8 +66,10 @@ void CSVReporter::ReportRuns(const std::vector& reports) { // save the names of all the user counters for (const auto& run : reports) { for (const auto& cnt : run.counters) { - if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second") + if (cnt.first == "bytes_per_second" || + cnt.first == "items_per_second") { continue; + } user_counter_names_.insert(cnt.first); } } @@ -75,7 +77,9 @@ void CSVReporter::ReportRuns(const std::vector& reports) { // print the header for (auto B = elements.begin(); B != elements.end();) { Out << *B++; - if (B != elements.end()) Out << ","; + if (B != elements.end()) { + Out << ","; + } } for (auto B = user_counter_names_.begin(); B != user_counter_names_.end();) { @@ -88,8 +92,10 @@ void CSVReporter::ReportRuns(const std::vector& reports) { // check that all the current counters are saved in the name set for (const auto& run : reports) { for (const auto& cnt : run.counters) { - if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second") + if (cnt.first == "bytes_per_second" || + cnt.first == "items_per_second") { continue; + } BM_CHECK(user_counter_names_.find(cnt.first) != user_counter_names_.end()) << "All counters must be present in each run. " diff --git a/src/json_reporter.cc b/src/json_reporter.cc index b8c8c94c08..2ab51d287d 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -89,11 +89,11 @@ std::string FormatKV(std::string const& key, double value) { std::stringstream ss; ss << '"' << StrEscape(key) << "\": "; - if (std::isnan(value)) + if (std::isnan(value)) { ss << (value < 0 ? "-" : "") << "NaN"; - else if (std::isinf(value)) + } else if (std::isinf(value)) { ss << (value < 0 ? "-" : "") << "Infinity"; - else { + } else { const auto max_digits10 = std::numeric_limits::max_digits10; const auto max_fractional_digits10 = max_digits10 - 1; @@ -155,7 +155,9 @@ bool JSONReporter::ReportContext(const Context& context) { << FormatKV("num_sharing", static_cast(CI.num_sharing)) << "\n"; out << indent << "}"; - if (i != info.caches.size() - 1) out << ","; + if (i != info.caches.size() - 1) { + out << ","; + } out << "\n"; } indent = std::string(4, ' '); @@ -163,7 +165,9 @@ bool JSONReporter::ReportContext(const Context& context) { out << indent << "\"load_avg\": ["; for (auto it = info.load_avg.begin(); it != info.load_avg.end();) { out << *it++; - if (it != info.load_avg.end()) out << ","; + if (it != info.load_avg.end()) { + out << ","; + } } out << "],\n"; @@ -306,8 +310,9 @@ void JSONReporter::PrintRunData(Run const& run) { auto report_if_present = [&out, &indent](const std::string& label, int64_t val) { - if (val != MemoryManager::TombstoneValue) + if (val != MemoryManager::TombstoneValue) { out << ",\n" << indent << FormatKV(label, val); + } }; report_if_present("total_allocated_bytes", diff --git a/src/reporter.cc b/src/reporter.cc index 076bc31a2e..263e969d8b 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -42,8 +42,9 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, Out << LocalDateTimeString() << "\n"; #endif - if (context.executable_name) + if (context.executable_name) { Out << "Running " << context.executable_name << "\n"; + } const CPUInfo &info = context.cpu_info; Out << "Run on (" << info.num_cpus << " X " @@ -54,8 +55,9 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, for (auto &CInfo : info.caches) { Out << " L" << CInfo.level << " " << CInfo.type << " " << (CInfo.size / 1024) << " KiB"; - if (CInfo.num_sharing != 0) + if (CInfo.num_sharing != 0) { Out << " (x" << (info.num_cpus / CInfo.num_sharing) << ")"; + } Out << "\n"; } } @@ -63,7 +65,9 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, Out << "Load Average: "; for (auto It = info.load_avg.begin(); It != info.load_avg.end();) { Out << StrFormat("%.2f", *It++); - if (It != info.load_avg.end()) Out << ", "; + if (It != info.load_avg.end()) { + Out << ", "; + } } Out << "\n"; } @@ -105,13 +109,17 @@ std::string BenchmarkReporter::Run::benchmark_name() const { double BenchmarkReporter::Run::GetAdjustedRealTime() const { double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit); - if (iterations != 0) new_time /= static_cast(iterations); + if (iterations != 0) { + new_time /= static_cast(iterations); + } return new_time; } double BenchmarkReporter::Run::GetAdjustedCPUTime() const { double new_time = cpu_accumulated_time * GetTimeUnitMultiplier(time_unit); - if (iterations != 0) new_time /= static_cast(iterations); + if (iterations != 0) { + new_time /= static_cast(iterations); + } return new_time; } diff --git a/src/statistics.cc b/src/statistics.cc index 16b60261fd..12eb5602d9 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -31,12 +31,16 @@ auto StatisticsSum = [](const std::vector& v) { }; double StatisticsMean(const std::vector& v) { - if (v.empty()) return 0.0; + if (v.empty()) { + return 0.0; + } return StatisticsSum(v) * (1.0 / static_cast(v.size())); } double StatisticsMedian(const std::vector& v) { - if (v.size() < 3) return StatisticsMean(v); + if (v.size() < 3) { + return StatisticsMean(v); + } std::vector copy(v); auto center = copy.begin() + v.size() / 2; @@ -47,7 +51,9 @@ double StatisticsMedian(const std::vector& v) { // before. Instead of resorting, we just look for the max value before it, // which is not necessarily the element immediately preceding `center` Since // `copy` is only partially sorted by `nth_element`. - if (v.size() % 2 == 1) return *center; + if (v.size() % 2 == 1) { + return *center; + } auto center2 = std::max_element(copy.begin(), center); return (*center + *center2) / 2.0; } @@ -60,16 +66,22 @@ auto SumSquares = [](const std::vector& v) { auto Sqr = [](const double dat) { return dat * dat; }; auto Sqrt = [](const double dat) { // Avoid NaN due to imprecision in the calculations - if (dat < 0.0) return 0.0; + if (dat < 0.0) { + return 0.0; + } return std::sqrt(dat); }; double StatisticsStdDev(const std::vector& v) { const auto mean = StatisticsMean(v); - if (v.empty()) return mean; + if (v.empty()) { + return mean; + } // Sample standard deviation is undefined for n = 1 - if (v.size() == 1) return 0.0; + if (v.size() == 1) { + return 0.0; + } const double avg_squares = SumSquares(v) * (1.0 / static_cast(v.size())); @@ -79,12 +91,16 @@ double StatisticsStdDev(const std::vector& v) { } double StatisticsCV(const std::vector& v) { - if (v.size() < 2) return 0.0; + if (v.size() < 2) { + return 0.0; + } const auto stddev = StatisticsStdDev(v); const auto mean = StatisticsMean(v); - if (std::fpclassify(mean) == FP_ZERO) return 0.0; + if (std::fpclassify(mean) == FP_ZERO) { + return 0.0; + } return stddev / mean; } @@ -137,7 +153,9 @@ std::vector ComputeStats( for (Run const& run : reports) { BM_CHECK_EQ(reports[0].benchmark_name(), run.benchmark_name()); BM_CHECK_EQ(run_iterations, run.iterations); - if (run.skipped) continue; + if (run.skipped) { + continue; + } real_accumulated_time_stat.emplace_back(run.real_accumulated_time); cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time); // user counters diff --git a/src/string_util.cc b/src/string_util.cc index 9ba63a700a..e0158a90f1 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -87,10 +87,14 @@ void ToExponentAndMantissa(double val, int precision, double one_k, } std::string ExponentToPrefix(int64_t exponent, bool iec) { - if (exponent == 0) return ""; + if (exponent == 0) { + return {}; + } const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1); - if (index >= kUnitsSize) return ""; + if (index >= kUnitsSize) { + return {}; + } const char* const* array = (exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits); @@ -124,9 +128,12 @@ std::string StrFormatImp(const char* msg, va_list args) { va_end(args_cp); // handle empty expansion - if (ret == 0) return std::string{}; - if (static_cast(ret) < local_buff.size()) + if (ret == 0) { + return {}; + } + if (static_cast(ret) < local_buff.size()) { return std::string(local_buff.data()); + } // we did not provide a long enough buffer on our first attempt. // add 1 to size to account for null-byte in size cast to prevent overflow @@ -153,7 +160,9 @@ std::string StrFormat(const char* format, ...) { } std::vector StrSplit(const std::string& str, char delim) { - if (str.empty()) return {}; + if (str.empty()) { + return {}; + } std::vector ret; size_t first = 0; size_t next = str.find(delim); diff --git a/src/sysinfo.cc b/src/sysinfo.cc index b1926ebe84..aeb06f8dfa 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -213,14 +213,18 @@ template bool ReadFromFile(std::string const& fname, ArgT* arg) { *arg = ArgT(); std::ifstream f(fname.c_str()); - if (!f.is_open()) return false; + if (!f.is_open()) { + return false; + } f >> *arg; return f.good(); } CPUInfo::Scaling CpuScaling(int num_cpus) { // We don't have a valid CPU count, so don't even bother. - if (num_cpus <= 0) return CPUInfo::Scaling::UNKNOWN; + if (num_cpus <= 0) { + return CPUInfo::Scaling::UNKNOWN; + } #if defined(BENCHMARK_OS_QNX) return CPUInfo::Scaling::UNKNOWN; #elif !defined(BENCHMARK_OS_WINDOWS) @@ -231,8 +235,9 @@ CPUInfo::Scaling CpuScaling(int num_cpus) { for (int cpu = 0; cpu < num_cpus; ++cpu) { std::string governor_file = StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor"); - if (ReadFromFile(governor_file, &res) && res != "performance") + if (ReadFromFile(governor_file, &res) && res != "performance") { return CPUInfo::Scaling::ENABLED; + } } return CPUInfo::Scaling::DISABLED; #else @@ -268,28 +273,35 @@ std::vector GetCacheSizesFromKVFS() { CPUInfo::CacheInfo info; std::string fpath = StrCat(dir, "index", idx++, "/"); std::ifstream f(StrCat(fpath, "size").c_str()); - if (!f.is_open()) break; + if (!f.is_open()) { + break; + } std::string suffix; f >> info.size; - if (f.fail()) + if (f.fail()) { PrintErrorAndDie("Failed while reading file '", fpath, "size'"); + } if (f.good()) { f >> suffix; - if (f.bad()) + if (f.bad()) { PrintErrorAndDie( "Invalid cache size format: failed to read size suffix"); - else if (f && suffix != "K") + } else if (f && suffix != "K") { PrintErrorAndDie("Invalid cache size format: Expected bytes ", suffix); - else if (suffix == "K") + } else if (suffix == "K") { info.size *= 1024; + } } - if (!ReadFromFile(StrCat(fpath, "type"), &info.type)) + if (!ReadFromFile(StrCat(fpath, "type"), &info.type)) { PrintErrorAndDie("Failed to read from file ", fpath, "type"); - if (!ReadFromFile(StrCat(fpath, "level"), &info.level)) + } + if (!ReadFromFile(StrCat(fpath, "level"), &info.level)) { PrintErrorAndDie("Failed to read from file ", fpath, "level"); + } std::string map_str; - if (!ReadFromFile(StrCat(fpath, "shared_cpu_map"), &map_str)) + if (!ReadFromFile(StrCat(fpath, "shared_cpu_map"), &map_str)) { PrintErrorAndDie("Failed to read from file ", fpath, "shared_cpu_map"); + } info.num_sharing = CountSetBitsInCPUMap(map_str); res.push_back(info); } @@ -334,15 +346,18 @@ std::vector GetCacheSizesWindows() { using UPtr = std::unique_ptr; GetLogicalProcessorInformation(nullptr, &buffer_size); UPtr buff(static_cast(std::malloc(buffer_size)), &std::free); - if (!GetLogicalProcessorInformation(buff.get(), &buffer_size)) + if (!GetLogicalProcessorInformation(buff.get(), &buffer_size)) { PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ", GetLastError()); + } PInfo* it = buff.get(); PInfo* end = buff.get() + (buffer_size / sizeof(PInfo)); for (; it != end; ++it) { - if (it->Relationship != RelationCache) continue; + if (it->Relationship != RelationCache) { + continue; + } using BitSet = std::bitset; BitSet b(it->ProcessorMask); // To prevent duplicates, only consider caches where CPU 0 is specified @@ -475,8 +490,7 @@ std::string GetSystemName() { #endif // def HOST_NAME_MAX char hostname[HOST_NAME_MAX]; int retVal = gethostname(hostname, HOST_NAME_MAX); - if (retVal != 0) return std::string(""); - return std::string(hostname); + return retVal != 0 ? std::string() : std::string(hostname); #endif // Catch-all POSIX block. } @@ -539,21 +553,28 @@ int GetNumCPUs() { class ThreadAffinityGuard final { public: ThreadAffinityGuard() : reset_affinity(SetAffinity()) { - if (!reset_affinity) + if (!reset_affinity) { std::cerr << "***WARNING*** Failed to set thread affinity. Estimated CPU " "frequency may be incorrect.\n"; + } } ~ThreadAffinityGuard() { - if (!reset_affinity) return; + if (!reset_affinity) { + return; + } #if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) int ret = pthread_setaffinity_np(self, sizeof(previous_affinity), &previous_affinity); - if (ret == 0) return; + if (ret == 0) { + return; + } #elif defined(BENCHMARK_OS_WINDOWS_WIN32) DWORD_PTR ret = SetThreadAffinityMask(self, previous_affinity); - if (ret != 0) return; + if (ret != 0) { + return; + } #endif // def BENCHMARK_HAS_PTHREAD_AFFINITY PrintErrorAndDie("Failed to reset thread affinity"); } @@ -570,22 +591,28 @@ class ThreadAffinityGuard final { self = pthread_self(); ret = pthread_getaffinity_np(self, sizeof(previous_affinity), &previous_affinity); - if (ret != 0) return false; + if (ret != 0) { + return false; + } cpu_set_t affinity; memcpy(&affinity, &previous_affinity, sizeof(affinity)); bool is_first_cpu = true; - for (int i = 0; i < CPU_SETSIZE; ++i) + for (int i = 0; i < CPU_SETSIZE; ++i) { if (CPU_ISSET(i, &affinity)) { - if (is_first_cpu) + if (is_first_cpu) { is_first_cpu = false; - else + } else { CPU_CLR(i, &affinity); + } } + } - if (is_first_cpu) return false; + if (is_first_cpu) { + return false; + } ret = pthread_setaffinity_np(self, sizeof(affinity), &affinity); return ret == 0; @@ -650,7 +677,9 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { } auto StartsWithKey = [](std::string const& Value, std::string const& Key) { - if (Key.size() > Value.size()) return false; + if (Key.size() > Value.size()) { + return false; + } auto Cmp = [&](char X, char Y) { return std::tolower(X) == std::tolower(Y); }; @@ -659,22 +688,30 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { std::string ln; while (std::getline(f, ln)) { - if (ln.empty()) continue; + if (ln.empty()) { + continue; + } std::size_t split_idx = ln.find(':'); std::string value; - if (split_idx != std::string::npos) value = ln.substr(split_idx + 1); + if (split_idx != std::string::npos) { + value = ln.substr(split_idx + 1); + } // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only // accept positive values. Some environments (virtual machines) report zero, // which would cause infinite looping in WallTime_Init. if (StartsWithKey(ln, "cpu MHz")) { if (!value.empty()) { double cycles_per_second = benchmark::stod(value) * 1000000.0; - if (cycles_per_second > 0) return cycles_per_second; + if (cycles_per_second > 0) { + return cycles_per_second; + } } } else if (StartsWithKey(ln, "bogomips")) { if (!value.empty()) { bogo_clock = benchmark::stod(value) * 1000000.0; - if (bogo_clock < 0.0) bogo_clock = error_value; + if (bogo_clock < 0.0) { + bogo_clock = error_value; + } } } } @@ -690,7 +727,9 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { // If we found the bogomips clock, but nothing better, we'll use it (but // we're not happy about it); otherwise, fallback to the rough estimation // below. - if (bogo_clock >= 0.0) return bogo_clock; + if (bogo_clock >= 0.0) { + return bogo_clock; + } #elif defined BENCHMARK_HAS_SYSCTL constexpr auto* freqStr = @@ -705,9 +744,13 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { #endif unsigned long long hz = 0; #if defined BENCHMARK_OS_OPENBSD - if (GetSysctl(freqStr, &hz)) return static_cast(hz * 1000000); + if (GetSysctl(freqStr, &hz)) { + return static_cast(hz * 1000000); + } #else - if (GetSysctl(freqStr, &hz)) return static_cast(hz); + if (GetSysctl(freqStr, &hz)) { + return static_cast(hz); + } #endif fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", freqStr, strerror(errno)); @@ -723,9 +766,10 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { SUCCEEDED( SHGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", - "~MHz", nullptr, &data, &data_size))) + "~MHz", nullptr, &data, &data_size))) { return static_cast(static_cast(data) * static_cast(1000 * 1000)); // was mhz + } #elif defined(BENCHMARK_OS_SOLARIS) kstat_ctl_t* kc = kstat_open(); if (!kc) { diff --git a/src/timers.cc b/src/timers.cc index a947fcf779..e0b32de0c3 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -144,8 +144,9 @@ double ProcessCPUUsage() { // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. // See https://github.com/google/benchmark/pull/292 struct timespec spec; - if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0) + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0) { return MakeTime(spec); + } DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed"); #else struct rusage ru; @@ -200,7 +201,9 @@ double ThreadCPUUsage() { DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed"); #elif defined(CLOCK_THREAD_CPUTIME_ID) struct timespec ts; - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts); + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) { + return MakeTime(ts); + } DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed"); #else #error Per-thread timing is not available on your system. diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index 4bb79730ae..56f0fbf2c2 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -47,7 +47,9 @@ int main(int argc, char** argv) { // Make a fake argv and append the new --benchmark_min_time= to it. int fake_argc = argc + 1; const char** fake_argv = new const char*[static_cast(fake_argc)]; - for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; + for (int i = 0; i < argc; ++i) { + fake_argv[i] = argv[i]; + } fake_argv[argc] = "--benchmark_min_time=4x"; benchmark::Initialize(&fake_argc, const_cast(fake_argv)); diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index 47e58a189a..0fc1fe9a54 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -73,7 +73,9 @@ int main(int argc, char** argv) { int fake_argc = argc + 1; const char** fake_argv = new const char*[static_cast(fake_argc)]; - for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; + for (int i = 0; i < argc; ++i) { + fake_argv[i] = argv[i]; + } const char* no_suffix = "--benchmark_min_time=4"; const char* with_suffix = "--benchmark_min_time=4.0s"; diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index 8b14017d03..b02274e40c 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -44,7 +44,9 @@ double CalculatePi(int depth) { std::set ConstructRandomSet(int64_t size) { std::set s; - for (int i = 0; i < size; ++i) s.insert(s.end(), i); + for (int i = 0; i < size; ++i) { + s.insert(s.end(), i); + } return s; } @@ -55,7 +57,9 @@ std::vector* test_vector = nullptr; static void BM_Factorial(benchmark::State& state) { int fac_42 = 0; - for (auto _ : state) fac_42 = Factorial(8); + for (auto _ : state) { + fac_42 = Factorial(8); + } // Prevent compiler optimizations std::stringstream ss; ss << fac_42; @@ -66,7 +70,9 @@ BENCHMARK(BM_Factorial)->UseRealTime(); static void BM_CalculatePiRange(benchmark::State& state) { double pi = 0.0; - for (auto _ : state) pi = CalculatePi(static_cast(state.range(0))); + for (auto _ : state) { + pi = CalculatePi(static_cast(state.range(0))); + } std::stringstream ss; ss << pi; state.SetLabel(ss.str()); @@ -90,7 +96,9 @@ static void BM_SetInsert(benchmark::State& state) { state.PauseTiming(); data = ConstructRandomSet(state.range(0)); state.ResumeTiming(); - for (int j = 0; j < state.range(1); ++j) data.insert(rand()); + for (int j = 0; j < state.range(1); ++j) { + data.insert(rand()); + } } state.SetItemsProcessed(state.iterations() * state.range(1)); state.SetBytesProcessed(state.iterations() * state.range(1) * @@ -108,7 +116,9 @@ static void BM_Sequential(benchmark::State& state) { ValueType v = 42; for (auto _ : state) { Container c; - for (int64_t i = state.range(0); --i;) c.push_back(v); + for (int64_t i = state.range(0); --i;) { + c.push_back(v); + } } const int64_t items_processed = state.iterations() * state.range(0); state.SetItemsProcessed(items_processed); @@ -141,10 +151,11 @@ static void BM_SetupTeardown(benchmark::State& state) { int i = 0; for (auto _ : state) { std::lock_guard l(test_vector_mu); - if (i % 2 == 0) + if (i % 2 == 0) { test_vector->push_back(i); - else + } else { test_vector->pop_back(); + } ++i; } if (state.thread_index() == 0) { @@ -156,8 +167,9 @@ BENCHMARK(BM_SetupTeardown)->ThreadPerCpu(); static void BM_LongTest(benchmark::State& state) { double tracker = 0.0; for (auto _ : state) { - for (int i = 0; i < state.range(0); ++i) + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(tracker += i); + } } } BENCHMARK(BM_LongTest)->Range(1 << 16, 1 << 28); diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index 2a7f887de3..69b21221c6 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -46,14 +46,18 @@ void try_invalid_pause_resume(benchmark::State& state) { void BM_diagnostic_test(benchmark::State& state) { static bool called_once = false; - if (called_once == false) try_invalid_pause_resume(state); + if (called_once == false) { + try_invalid_pause_resume(state); + } for (auto _ : state) { auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } - if (called_once == false) try_invalid_pause_resume(state); + if (called_once == false) { + try_invalid_pause_resume(state); + } called_once = true; } @@ -62,14 +66,18 @@ BENCHMARK(BM_diagnostic_test); void BM_diagnostic_test_keep_running(benchmark::State& state) { static bool called_once = false; - if (called_once == false) try_invalid_pause_resume(state); + if (called_once == false) { + try_invalid_pause_resume(state); + } while (state.KeepRunning()) { auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } - if (called_once == false) try_invalid_pause_resume(state); + if (called_once == false) { + try_invalid_pause_resume(state); + } called_once = true; } diff --git a/test/filter_test.cc b/test/filter_test.cc index d2d4d96ebd..1e4dd2ec59 100644 --- a/test/filter_test.cc +++ b/test/filter_test.cc @@ -71,9 +71,10 @@ BENCHMARK(BM_FooBa); int main(int argc, char** argv) { bool list_only = false; - for (int i = 0; i < argc; ++i) + for (int i = 0; i < argc; ++i) { list_only |= std::string(argv[i]).find("--benchmark_list_tests") != std::string::npos; + } benchmark::Initialize(&argc, argv); diff --git a/test/internal_threading_test.cc b/test/internal_threading_test.cc index 62b5b955a9..6984ff853b 100644 --- a/test/internal_threading_test.cc +++ b/test/internal_threading_test.cc @@ -22,8 +22,9 @@ void MyBusySpinwait() { const auto elapsed = now - start; if (std::chrono::duration(elapsed) >= - time_frame) + time_frame) { return; + } } } diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index b7c3c510ae..e48b465483 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -112,7 +112,9 @@ void CheckCase(std::stringstream& remaining_output, TestCase const& TC, << "\n actual regex string \"" << TC.substituted_regex << "\"" << "\n started matching near: " << first_line; } - if (TC.regex->Match(line)) return; + if (TC.regex->Match(line)) { + return; + } BM_CHECK(TC.match_rule != MR_Next) << "Expected line \"" << line << "\" to match regex \"" << TC.regex_str << "\"" @@ -159,10 +161,14 @@ class TestReporter : public benchmark::BenchmarkReporter { } void ReportRuns(const std::vector& report) override { - for (auto rep : reporters_) rep->ReportRuns(report); + for (auto rep : reporters_) { + rep->ReportRuns(report); + } } void Finalize() override { - for (auto rep : reporters_) rep->Finalize(); + for (auto rep : reporters_) { + rep->Finalize(); + } } private: @@ -224,7 +230,9 @@ void ResultsChecker::CheckResults(std::stringstream& output) { // clear before calling tellg() output.clear(); // seek to zero only when needed - if (output.tellg() > start) output.seekg(start); + if (output.tellg() > start) { + output.seekg(start); + } // and just in case output.clear(); } @@ -265,7 +273,9 @@ void ResultsChecker::SetHeader_(const std::string& csv_header) { // set the values for a benchmark void ResultsChecker::SetValues_(const std::string& entry_csv_line) { - if (entry_csv_line.empty()) return; // some lines are empty + if (entry_csv_line.empty()) { + return; + } // some lines are empty BM_CHECK(!field_names.empty()); auto vals = SplitCsv_(entry_csv_line); BM_CHECK_EQ(vals.size(), field_names.size()); @@ -279,21 +289,33 @@ void ResultsChecker::SetValues_(const std::string& entry_csv_line) { // a quick'n'dirty csv splitter (eliminating quotes) std::vector ResultsChecker::SplitCsv_(const std::string& line) { std::vector out; - if (line.empty()) return out; - if (!field_names.empty()) out.reserve(field_names.size()); + if (line.empty()) { + return out; + } + if (!field_names.empty()) { + out.reserve(field_names.size()); + } size_t prev = 0, pos = line.find_first_of(','), curr = pos; while (pos != line.npos) { BM_CHECK(curr > 0); - if (line[prev] == '"') ++prev; - if (line[curr - 1] == '"') --curr; + if (line[prev] == '"') { + ++prev; + } + if (line[curr - 1] == '"') { + --curr; + } out.push_back(line.substr(prev, curr - prev)); prev = pos + 1; pos = line.find_first_of(',', pos + 1); curr = pos; } curr = line.size(); - if (line[prev] == '"') ++prev; - if (line[curr - 1] == '"') --curr; + if (line[prev] == '"') { + ++prev; + } + if (line[curr - 1] == '"') { + --curr; + } out.push_back(line.substr(prev, curr - prev)); return out; } @@ -308,7 +330,9 @@ size_t AddChecker(const std::string& bm_name, const ResultsCheckFn& fn) { int Results::NumThreads() const { auto pos = name.find("/threads:"); - if (pos == name.npos) return 1; + if (pos == name.npos) { + return 1; + } auto end = name.find('/', pos + 9); std::stringstream ss; ss << name.substr(pos + 9, end); @@ -378,7 +402,9 @@ int SetSubstitutions( break; } } - if (!exists) subs.push_back(std::move(KV)); + if (!exists) { + subs.push_back(std::move(KV)); + } } return 0; } @@ -449,11 +475,14 @@ void RunOutputTests(int argc, char* argv[]) { BENCHMARK_RESTORE_DEPRECATED_WARNING int SubstrCnt(const std::string& haystack, const std::string& pat) { - if (pat.length() == 0) return 0; + if (pat.length() == 0) { + return 0; + } int count = 0; for (size_t offset = haystack.find(pat); offset != std::string::npos; - offset = haystack.find(pat, offset + pat.length())) + offset = haystack.find(pat, offset + pat.length())) { ++count; + } return count; } @@ -471,7 +500,9 @@ static char RandomHexChar() { static std::string GetRandomFileName() { std::string model = "test.%%%%%%"; for (auto& ch : model) { - if (ch == '%') ch = RandomHexChar(); + if (ch == '%') { + ch = RandomHexChar(); + } } return model; } @@ -488,7 +519,9 @@ static std::string GetTempFileName() { int retries = 3; while (--retries) { std::string name = GetRandomFileName(); - if (!FileExists(name)) return name; + if (!FileExists(name)) { + return name; + } } std::cerr << "Failed to create unique temporary file name\n"; std::flush(std::cerr); diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index 2e63049285..5de262fa2b 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -226,9 +226,13 @@ void measure(size_t threadcount, PerfCounterValues* before, // threadpool. auto counters = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}); - for (auto& t : threads) t = std::thread(work); + for (auto& t : threads) { + t = std::thread(work); + } counters.Snapshot(before); - for (auto& t : threads) t.join(); + for (auto& t : threads) { + t.join(); + } counters.Snapshot(after); } diff --git a/test/profiler_manager_iterations_test.cc b/test/profiler_manager_iterations_test.cc index e727929ddb..6b475f7888 100644 --- a/test/profiler_manager_iterations_test.cc +++ b/test/profiler_manager_iterations_test.cc @@ -39,7 +39,9 @@ int main(int argc, char** argv) { // to it. int fake_argc = argc + 1; const char** fake_argv = new const char*[static_cast(fake_argc)]; - for (int i = 0; i < argc; ++i) fake_argv[i] = argv[i]; + for (int i = 0; i < argc; ++i) { + fake_argv[i] = argv[i]; + } fake_argv[argc] = "--benchmark_min_time=4x"; std::unique_ptr pm(new TestProfilerManager()); diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index d69d144a4e..e2f911e184 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -86,8 +86,9 @@ void BM_extra_args(benchmark::State& st, const char* label) { int RegisterFromFunction() { std::pair cases[] = { {"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}}; - for (auto const& c : cases) + for (auto const& c : cases) { benchmark::RegisterBenchmark(c.first, &BM_extra_args, c.second); + } return 0; } int dummy2 = RegisterFromFunction(); diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 2139a19e25..040bd4219c 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -146,8 +146,9 @@ void BM_error_after_running(benchmark::State& state) { auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); } - if (state.thread_index() <= (state.threads() / 2)) + if (state.thread_index() <= (state.threads() / 2)) { state.SkipWithError("error message"); + } } BENCHMARK(BM_error_after_running)->ThreadRange(1, 8); ADD_CASES("BM_error_after_running", {{"/threads:1", true, "error message"}, diff --git a/test/user_counters_thousands_test.cc b/test/user_counters_thousands_test.cc index fc153835f8..dd4efd4f44 100644 --- a/test/user_counters_thousands_test.cc +++ b/test/user_counters_thousands_test.cc @@ -166,8 +166,9 @@ ADD_CASES( // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() void CheckThousands(Results const& e) { - if (e.name != "BM_Counters_Thousands/repeats:2") + if (e.name != "BM_Counters_Thousands/repeats:2") { return; // Do not check the aggregates! + } // check that the values are within 0.01% of the expected values CHECK_FLOAT_COUNTER_VALUE(e, "t0_1000000DefaultBase", EQ, 1000 * 1000, From 2d4c8dd21a29f1d7748120a62aa80e609fdf2e87 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 12 Feb 2025 11:32:45 -0800 Subject: [PATCH 315/561] [clang-tidy] autofix cppcoreguidelines (#1932) * [clang-tidy] autofix cppcoreguidelines * better than automation maybe --- include/benchmark/benchmark.h | 2 +- src/benchmark_runner.cc | 6 +++--- src/benchmark_runner.h | 2 +- src/string_util.cc | 4 ++-- src/sysinfo.cc | 10 +++++----- src/timers.cc | 12 ++++++------ test/benchmark_min_time_flag_iters_test.cc | 6 +++--- test/benchmark_min_time_flag_time_test.cc | 10 +++++----- test/filter_test.cc | 2 +- test/output_test_helper.cc | 2 +- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 0b0b6e9aac..f432205183 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1692,7 +1692,7 @@ class BENCHMARK_EXPORT BenchmarkReporter { CPUInfo const& cpu_info; SystemInfo const& sys_info; // The number of chars in the longest benchmark name. - size_t name_field_width; + size_t name_field_width = 0; static const char* executable_name; Context(); }; diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 388953c131..406892a154 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -186,7 +186,7 @@ IterationCount ComputeIters(const benchmark::internal::BenchmarkInstance& b, } // end namespace BenchTimeType ParseBenchMinTime(const std::string& value) { - BenchTimeType ret; + BenchTimeType ret = {}; if (value.empty()) { ret.tag = BenchTimeType::TIME; @@ -195,7 +195,7 @@ BenchTimeType ParseBenchMinTime(const std::string& value) { } if (value.back() == 'x') { - char* p_end; + char* p_end = nullptr; // Reset errno before it's changed by strtol. errno = 0; IterationCount num_iters = std::strtol(value.c_str(), &p_end, 10); @@ -217,7 +217,7 @@ BenchTimeType ParseBenchMinTime(const std::string& value) { "Eg., `30s` for 30-seconds."; } - char* p_end; + char* p_end = nullptr; // Reset errno before it's changed by strtod. errno = 0; double min_time = std::strtod(value.c_str(), &p_end); diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index 20a37c1ae3..2e43ff40c0 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -38,7 +38,7 @@ struct RunResults { }; struct BENCHMARK_EXPORT BenchTimeType { - enum { ITERS, TIME } tag; + enum { UNSPECIFIED, ITERS, TIME } tag; union { IterationCount iters; double time; diff --git a/src/string_util.cc b/src/string_util.cc index e0158a90f1..e50812eaff 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -105,7 +105,7 @@ std::string ExponentToPrefix(int64_t exponent, bool iec) { std::string ToBinaryStringFullySpecified(double value, int precision, Counter::OneK one_k) { std::string mantissa; - int64_t exponent; + int64_t exponent = 0; ToExponentAndMantissa(value, precision, one_k == Counter::kIs1024 ? 1024.0 : 1000.0, &mantissa, &exponent); @@ -119,7 +119,7 @@ std::string StrFormatImp(const char* msg, va_list args) { // TODO(ericwf): use std::array for first attempt to avoid one memory // allocation guess what the size might be - std::array local_buff; + std::array local_buff = {}; // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation // in the android-ndk diff --git a/src/sysinfo.cc b/src/sysinfo.cc index aeb06f8dfa..89518a93bf 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -252,7 +252,7 @@ int CountSetBitsInCPUMap(std::string val) { CPUMask mask(benchmark::stoul(part, nullptr, 16)); return static_cast(mask.count()); }; - std::size_t pos; + std::size_t pos = 0; int total = 0; while ((pos = val.find(',')) != std::string::npos) { total += CountBits(val.substr(0, pos)); @@ -587,7 +587,7 @@ class ThreadAffinityGuard final { private: bool SetAffinity() { #if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) - int ret; + int ret = 0; self = pthread_self(); ret = pthread_getaffinity_np(self, sizeof(previous_affinity), &previous_affinity); @@ -627,8 +627,8 @@ class ThreadAffinityGuard final { } #if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) - pthread_t self; - cpu_set_t previous_affinity; + pthread_t self{}; + cpu_set_t previous_affinity{}; #elif defined(BENCHMARK_OS_WINDOWS_WIN32) HANDLE self; DWORD_PTR previous_affinity; @@ -642,7 +642,7 @@ double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) { (void)scaling; #if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN - long freq; + long freq = 0; // If the kernel is exporting the tsc frequency use that. There are issues // where cpuinfo_max_freq cannot be relied on because the BIOS may be diff --git a/src/timers.cc b/src/timers.cc index e0b32de0c3..adaab3ab56 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -143,7 +143,7 @@ double ProcessCPUUsage() { #elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX) // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. // See https://github.com/google/benchmark/pull/292 - struct timespec spec; + struct timespec spec {}; if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0) { return MakeTime(spec); } @@ -200,7 +200,7 @@ double ThreadCPUUsage() { if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru); DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed"); #elif defined(CLOCK_THREAD_CPUTIME_ID) - struct timespec ts; + struct timespec ts {}; if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) { return MakeTime(ts); } @@ -217,9 +217,9 @@ std::string LocalDateTimeString() { const std::size_t kTzOffsetLen = 6; const std::size_t kTimestampLen = 19; - std::size_t tz_len; - std::size_t timestamp_len; - long int offset_minutes; + std::size_t tz_len = 0; + std::size_t timestamp_len = 0; + long int offset_minutes = 0; char tz_offset_sign = '+'; // tz_offset is set in one of three ways: // * strftime with %z - This either returns empty or the ISO 8601 time. The @@ -239,7 +239,7 @@ std::string LocalDateTimeString() { #if defined(BENCHMARK_OS_WINDOWS) std::tm* timeinfo_p = ::localtime(&now); #else - std::tm timeinfo; + std::tm timeinfo{}; std::tm* timeinfo_p = &timeinfo; ::localtime_r(&now, &timeinfo); #endif diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index 56f0fbf2c2..60d512d0ea 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -13,11 +13,11 @@ namespace { class TestReporter : public benchmark::ConsoleReporter { public: - virtual bool ReportContext(const Context& context) override { + bool ReportContext(const Context& context) override { return ConsoleReporter::ReportContext(context); }; - virtual void ReportRuns(const std::vector& report) override { + void ReportRuns(const std::vector& report) override { assert(report.size() == 1); iter_nums_.push_back(report[0].iterations); ConsoleReporter::ReportRuns(report); @@ -25,7 +25,7 @@ class TestReporter : public benchmark::ConsoleReporter { TestReporter() {} - virtual ~TestReporter() {} + ~TestReporter() override {} const std::vector& GetIters() const { return iter_nums_; diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index 0fc1fe9a54..95a83f5441 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -19,23 +19,23 @@ typedef int64_t IterationCount; class TestReporter : public benchmark::ConsoleReporter { public: - virtual bool ReportContext(const Context& context) override { + bool ReportContext(const Context& context) override { return ConsoleReporter::ReportContext(context); }; - virtual void ReportRuns(const std::vector& report) override { + void ReportRuns(const std::vector& report) override { assert(report.size() == 1); ConsoleReporter::ReportRuns(report); }; - virtual void ReportRunsConfig(double min_time, bool /* has_explicit_iters */, - IterationCount /* iters */) override { + void ReportRunsConfig(double min_time, bool /* has_explicit_iters */, + IterationCount /* iters */) override { min_times_.push_back(min_time); } TestReporter() {} - virtual ~TestReporter() {} + ~TestReporter() override {} const std::vector& GetMinTimes() const { return min_times_; } diff --git a/test/filter_test.cc b/test/filter_test.cc index 1e4dd2ec59..a931a68e0f 100644 --- a/test/filter_test.cc +++ b/test/filter_test.cc @@ -85,7 +85,7 @@ int main(int argc, char** argv) { if (argc == 2) { // Make sure we ran all of the tests std::stringstream ss(argv[1]); - int64_t expected_return; + int64_t expected_return = 0; ss >> expected_return; if (returned_count != expected_return) { diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index e48b465483..73ce2bcfd6 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -83,7 +83,7 @@ std::string PerformSubstitutions(std::string source) { SubMap const& subs = GetSubstitutions(); using SizeT = std::string::size_type; for (auto const& KV : subs) { - SizeT pos; + SizeT pos = 0; SizeT next_start = 0; while ((pos = source.find(KV.first, next_start)) != std::string::npos) { next_start = pos + KV.second.size(); From adbda82db30a741df5902ecc8bee33a79e57ee2c Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 12 Feb 2025 11:40:49 -0800 Subject: [PATCH 316/561] [clang-tidy] autofix readability issues (#1931) * [clang-tidy] autofix readability issues * more modern clang format --- .github/workflows/clang-format-lint.yml | 6 +- include/benchmark/benchmark.h | 14 +- src/benchmark.cc | 33 ++-- src/benchmark_api_internal.cc | 4 +- src/benchmark_api_internal.h | 6 +- src/benchmark_main.cc | 2 +- src/benchmark_name.cc | 4 +- src/benchmark_register.cc | 8 +- src/benchmark_runner.cc | 25 +-- src/benchmark_runner.h | 2 +- src/colorprint.cc | 4 +- src/commandlineflags.cc | 2 +- src/console_reporter.cc | 23 +-- src/counter.cc | 10 +- src/csv_reporter.cc | 2 +- src/json_reporter.cc | 16 +- src/reporter.cc | 9 +- src/statistics.cc | 4 +- src/string_util.cc | 2 +- src/sysinfo.cc | 3 +- src/timers.cc | 2 +- test/basic_test.cc | 3 +- test/benchmark_random_interleaving_gtest.cc | 2 +- test/benchmark_setup_teardown_test.cc | 6 +- test/diagnostics_test.cc | 14 +- test/donotoptimize_test.cc | 4 +- test/link_main_test.cc | 3 +- test/map_test.cc | 2 +- test/memory_manager_test.cc | 3 +- test/output_test_helper.cc | 29 +-- test/register_benchmark_test.cc | 2 +- test/reporter_output_test.cc | 9 +- test/skip_with_error_test.cc | 7 +- test/string_util_gtest.cc | 184 ++++++++++---------- test/time_unit_gtest.cc | 2 +- test/user_counters_tabular_test.cc | 6 +- test/user_counters_test.cc | 21 ++- 37 files changed, 253 insertions(+), 225 deletions(-) diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 8f089dc8dc..de3e5912f6 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -10,9 +10,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: DoozyX/clang-format-lint-action@v0.15 + - uses: DoozyX/clang-format-lint-action@v0.18.2 with: source: './include/benchmark ./src ./test' - extensions: 'h,cc' - clangFormatVersion: 12 - style: Google + clangFormatVersion: 18 diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index f432205183..eec0fc58c3 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -313,7 +313,7 @@ BENCHMARK_EXPORT std::string GetBenchmarkVersion(); BENCHMARK_EXPORT void PrintDefaultHelp(); BENCHMARK_EXPORT void Initialize(int* argc, char** argv, - void (*HelperPrinterf)() = PrintDefaultHelp); + void (*HelperPrintf)() = PrintDefaultHelp); BENCHMARK_EXPORT void Shutdown(); // Report to stdout all arguments in 'argv' as unrecognized except the first. @@ -631,7 +631,7 @@ class Counter { Counter(double v = 0., Flags f = kDefaults, OneK k = kIs1000) : value(v), flags(f), oneK(k) {} - BENCHMARK_ALWAYS_INLINE operator double const &() const { return value; } + BENCHMARK_ALWAYS_INLINE operator double const&() const { return value; } BENCHMARK_ALWAYS_INLINE operator double&() { return value; } }; @@ -1165,7 +1165,7 @@ class BENCHMARK_EXPORT Benchmark { // Pass this benchmark object to *func, which can customize // the benchmark by calling various methods like Arg, Args, // Threads, etc. - Benchmark* Apply(void (*func)(Benchmark* benchmark)); + Benchmark* Apply(void (*custom_arguments)(Benchmark* benchmark)); // Set the range multiplier for non-dense range. If not called, the range // multiplier kRangeMultiplier will be used. @@ -1869,8 +1869,8 @@ class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter { void ReportRuns(const std::vector& reports) override; protected: - virtual void PrintRunData(const Run& report); - virtual void PrintHeader(const Run& report); + virtual void PrintRunData(const Run& result); + virtual void PrintHeader(const Run& run); OutputOptions output_options_; size_t name_field_width_; @@ -1886,7 +1886,7 @@ class BENCHMARK_EXPORT JSONReporter : public BenchmarkReporter { void Finalize() override; private: - void PrintRunData(const Run& report); + void PrintRunData(const Run& run); bool first_report_; }; @@ -1900,7 +1900,7 @@ class BENCHMARK_EXPORT BENCHMARK_DEPRECATED_MSG( void ReportRuns(const std::vector& reports) override; private: - void PrintRunData(const Run& report); + void PrintRunData(const Run& run); bool printed_header_; std::set user_counter_names_; diff --git a/src/benchmark.cc b/src/benchmark.cc index 0c14137475..a1f71b7186 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -46,7 +46,6 @@ #include "commandlineflags.h" #include "complexity.h" #include "counter.h" -#include "internal_macros.h" #include "log.h" #include "mutex.h" #include "perf_counters.h" @@ -198,7 +197,7 @@ State::State(std::string name, IterationCount max_iters, // `PauseTiming`, a new `Counter` will be inserted the first time, which // won't have the flag. Inserting them now also reduces the allocations // during the benchmark. - if (perf_counters_measurement_) { + if (perf_counters_measurement_ != nullptr) { for (const std::string& counter_name : perf_counters_measurement_->names()) { counters[counter_name] = Counter(0.0, Counter::kAvgIterations); @@ -247,7 +246,7 @@ void State::PauseTiming() { // Add in time accumulated so far BM_CHECK(started_ && !finished_ && !skipped()); timer_->StopTimer(); - if (perf_counters_measurement_) { + if (perf_counters_measurement_ != nullptr) { std::vector> measurements; if (!perf_counters_measurement_->Stop(measurements)) { BM_CHECK(false) << "Perf counters read the value failed."; @@ -265,7 +264,7 @@ void State::PauseTiming() { void State::ResumeTiming() { BM_CHECK(started_ && !finished_ && !skipped()); timer_->StartTimer(); - if (perf_counters_measurement_) { + if (perf_counters_measurement_ != nullptr) { perf_counters_measurement_->Start(); } } @@ -342,7 +341,7 @@ namespace { // Flushes streams after invoking reporter methods that write to them. This // ensures users get timely updates even when streams are not line-buffered. void FlushStreams(BenchmarkReporter* reporter) { - if (!reporter) { + if (reporter == nullptr) { return; } std::flush(reporter->GetOutputStream()); @@ -367,7 +366,7 @@ void Report(BenchmarkReporter* display_reporter, report_one(display_reporter, run_results.display_report_aggregates_only, run_results); - if (file_reporter) { + if (file_reporter != nullptr) { report_one(file_reporter, run_results.file_report_aggregates_only, run_results); } @@ -408,7 +407,7 @@ void RunBenchmarks(const std::vector& benchmarks, per_family_reports; if (display_reporter->ReportContext(context) && - (!file_reporter || file_reporter->ReportContext(context))) { + ((file_reporter == nullptr) || file_reporter->ReportContext(context))) { FlushStreams(display_reporter); FlushStreams(file_reporter); @@ -433,12 +432,12 @@ void RunBenchmarks(const std::vector& benchmarks, if (benchmark.complexity() != oNone) { reports_for_family = &per_family_reports[benchmark.family_index()]; } - benchmarks_with_threads += (benchmark.threads() > 1); + benchmarks_with_threads += static_cast(benchmark.threads() > 1); runners.emplace_back(benchmark, &perfcounters, reports_for_family); int num_repeats_of_this_instance = runners.back().GetNumRepeats(); num_repetitions_total += static_cast(num_repeats_of_this_instance); - if (reports_for_family) { + if (reports_for_family != nullptr) { reports_for_family->num_runs_total += num_repeats_of_this_instance; } } @@ -482,7 +481,7 @@ void RunBenchmarks(const std::vector& benchmarks, display_reporter->ReportRunsConfig( runner.GetMinTime(), runner.HasExplicitIters(), runner.GetIters()); - if (file_reporter) { + if (file_reporter != nullptr) { file_reporter->ReportRunsConfig( runner.GetMinTime(), runner.HasExplicitIters(), runner.GetIters()); } @@ -506,7 +505,7 @@ void RunBenchmarks(const std::vector& benchmarks, } } display_reporter->Finalize(); - if (file_reporter) { + if (file_reporter != nullptr) { file_reporter->Finalize(); } FlushStreams(display_reporter); @@ -569,7 +568,7 @@ ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color) { } // end namespace internal BenchmarkReporter* CreateDefaultDisplayReporter() { - static auto default_display_reporter = + static auto* default_display_reporter = internal::CreateReporter(FLAGS_benchmark_format, internal::GetOutputOptions()) .release(); @@ -611,7 +610,7 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, std::ofstream output_file; std::unique_ptr default_display_reporter; std::unique_ptr default_file_reporter; - if (!display_reporter) { + if (display_reporter == nullptr) { default_display_reporter.reset(CreateDefaultDisplayReporter()); display_reporter = default_display_reporter.get(); } @@ -619,7 +618,7 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, auto& Err = display_reporter->GetErrorStream(); std::string const& fname = FLAGS_benchmark_out; - if (fname.empty() && file_reporter) { + if (fname.empty() && (file_reporter != nullptr)) { Err << "A custom file reporter was provided but " "--benchmark_out= was not specified.\n"; Out.flush(); @@ -634,7 +633,7 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, Err.flush(); std::exit(1); } - if (!file_reporter) { + if (file_reporter == nullptr) { default_file_reporter = internal::CreateReporter( FLAGS_benchmark_out_format, FLAGS_benchmark_counters_tabular ? ConsoleReporter::OO_Tabular @@ -743,8 +742,8 @@ void SetDefaultTimeUnitFromFlag(const std::string& time_unit_flag) { void ParseCommandLineFlags(int* argc, char** argv) { using namespace benchmark; BenchmarkReporter::Context::executable_name = - (argc && *argc > 0) ? argv[0] : "unknown"; - for (int i = 1; argc && i < *argc; ++i) { + ((argc != nullptr) && *argc > 0) ? argv[0] : "unknown"; + for (int i = 1; (argc != nullptr) && i < *argc; ++i) { if (ParseBoolFlag(argv[i], "benchmark_list_tests", &FLAGS_benchmark_list_tests) || ParseStringFlag(argv[i], "benchmark_filter", &FLAGS_benchmark_filter) || diff --git a/src/benchmark_api_internal.cc b/src/benchmark_api_internal.cc index 4b569d7982..14d4e1341d 100644 --- a/src/benchmark_api_internal.cc +++ b/src/benchmark_api_internal.cc @@ -101,7 +101,7 @@ State BenchmarkInstance::Run( } void BenchmarkInstance::Setup() const { - if (setup_) { + if (setup_ != nullptr) { State st(name_.function_name, /*iters*/ 1, args_, /*thread_id*/ 0, threads_, nullptr, nullptr, nullptr, nullptr); setup_(st); @@ -109,7 +109,7 @@ void BenchmarkInstance::Setup() const { } void BenchmarkInstance::Teardown() const { - if (teardown_) { + if (teardown_ != nullptr) { State st(name_.function_name, /*iters*/ 1, args_, /*thread_id*/ 0, threads_, nullptr, nullptr, nullptr, nullptr); teardown_(st); diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h index 659a71440e..9287c4eb43 100644 --- a/src/benchmark_api_internal.h +++ b/src/benchmark_api_internal.h @@ -17,9 +17,9 @@ namespace internal { // Information kept per benchmark we may want to run class BenchmarkInstance { public: - BenchmarkInstance(Benchmark* benchmark, int family_index, - int per_family_instance_index, - const std::vector& args, int threads); + BenchmarkInstance(Benchmark* benchmark, int family_idx, + int per_family_instance_idx, + const std::vector& args, int thread_count); const BenchmarkName& name() const { return name_; } int family_index() const { return family_index_; } diff --git a/src/benchmark_main.cc b/src/benchmark_main.cc index cd61cd2ad5..15c76eaceb 100644 --- a/src/benchmark_main.cc +++ b/src/benchmark_main.cc @@ -14,5 +14,5 @@ #include "benchmark/benchmark.h" -BENCHMARK_EXPORT int main(int, char**); +BENCHMARK_EXPORT int main(int /*argc*/, char** /*argv*/); BENCHMARK_MAIN(); diff --git a/src/benchmark_name.cc b/src/benchmark_name.cc index 01676bbc84..804cfbd3b7 100644 --- a/src/benchmark_name.cc +++ b/src/benchmark_name.cc @@ -27,8 +27,8 @@ size_t size_impl(const Head& head, const Tail&... tail) { } // Join a pack of std::strings using a delimiter -// TODO: use absl::StrJoin -void join_impl(std::string&, char) {} +// TODO(dominic): use absl::StrJoin +void join_impl(std::string& /*unused*/, char /*unused*/) {} template void join_impl(std::string& s, const char delimiter, const Head& head, diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 23934b0efb..28336a1644 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -53,13 +53,13 @@ namespace benchmark { namespace { // For non-dense Range, intermediate values are powers of kRangeMultiplier. -static constexpr int kRangeMultiplier = 8; +constexpr int kRangeMultiplier = 8; // The size of a benchmark family determines is the number of inputs to repeat // the benchmark on. If this is "large" then warn the user during configuration. -static constexpr size_t kMaxFamilySize = 100; +constexpr size_t kMaxFamilySize = 100; -static constexpr char kDisabledPrefix[] = "DISABLED_"; +constexpr char kDisabledPrefix[] = "DISABLED_"; } // end namespace namespace internal { @@ -82,7 +82,7 @@ class BenchmarkFamilies { // Extract the list of benchmark instances that match the specified // regular expression. - bool FindBenchmarks(std::string re, + bool FindBenchmarks(std::string spec, std::vector* benchmarks, std::ostream* Err); diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 406892a154..b7d3de3db5 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -46,7 +46,6 @@ #include "commandlineflags.h" #include "complexity.h" #include "counter.h" -#include "internal_macros.h" #include "log.h" #include "mutex.h" #include "perf_counters.h" @@ -74,7 +73,7 @@ ProfilerManager* profiler_manager = nullptr; namespace { -static constexpr IterationCount kMaxIterations = 1000000000000; +constexpr IterationCount kMaxIterations = 1000000000000; const double kDefaultMinTime = std::strtod(::benchmark::kDefaultMinTimeStr, /*p_end*/ nullptr); @@ -100,7 +99,7 @@ BenchmarkReporter::Run CreateRunReport( report.repetition_index = repetition_index; report.repetitions = repeats; - if (!report.skipped) { + if (report.skipped == 0u) { if (b.use_manual_time()) { report.real_accumulated_time = results.manual_time_used; } else { @@ -118,9 +117,10 @@ BenchmarkReporter::Run CreateRunReport( assert(memory_result != nullptr); report.memory_result = memory_result; report.allocs_per_iter = - memory_iterations ? static_cast(memory_result->num_allocs) / - static_cast(memory_iterations) - : 0; + memory_iterations != 0 + ? static_cast(memory_result->num_allocs) / + static_cast(memory_iterations) + : 0; } internal::Finish(&report.counters, results.iterations, seconds, @@ -273,10 +273,11 @@ BenchmarkRunner::BenchmarkRunner( FLAGS_benchmark_report_aggregates_only; if (b.aggregation_report_mode() != internal::ARM_Unspecified) { run_results.display_report_aggregates_only = - (b.aggregation_report_mode() & - internal::ARM_DisplayReportAggregatesOnly); + ((b.aggregation_report_mode() & + internal::ARM_DisplayReportAggregatesOnly) != 0u); run_results.file_report_aggregates_only = - (b.aggregation_report_mode() & internal::ARM_FileReportAggregatesOnly); + ((b.aggregation_report_mode() & + internal::ARM_FileReportAggregatesOnly) != 0u); BM_CHECK(FLAGS_benchmark_perf_counters.empty() || (perf_counters_measurement_ptr->num_counters() == 0)) << "Perf counters were requested but could not be set up."; @@ -364,7 +365,7 @@ bool BenchmarkRunner::ShouldReportIterationResults( // Determine if this run should be reported; // Either it has run for a sufficient amount of time // or because an error was reported. - return i.results.skipped_ || FLAGS_benchmark_dry_run || + return (i.results.skipped_ != 0u) || FLAGS_benchmark_dry_run || i.iters >= kMaxIterations || // Too many iterations already. i.seconds >= GetMinTimeToApply() || // The elapsed time is large enough. @@ -528,9 +529,9 @@ void BenchmarkRunner::DoOneRepetition() { CreateRunReport(b, i.results, memory_iterations, memory_result, i.seconds, num_repetitions_done, repeats); - if (reports_for_family) { + if (reports_for_family != nullptr) { ++reports_for_family->num_runs_done; - if (!report.skipped) { + if (report.skipped == 0u) { reports_for_family->Runs.push_back(report); } } diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index 2e43ff40c0..965087eb00 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -51,7 +51,7 @@ BenchTimeType ParseBenchMinTime(const std::string& value); class BenchmarkRunner { public: BenchmarkRunner(const benchmark::internal::BenchmarkInstance& b_, - benchmark::internal::PerfCountersMeasurement* pmc_, + benchmark::internal::PerfCountersMeasurement* pcm_, BenchmarkReporter::PerFamilyRunReports* reports_for_family); int GetNumRepeats() const { return repeats; } diff --git a/src/colorprint.cc b/src/colorprint.cc index e7d7a2d2a8..c90232f20f 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -156,7 +156,7 @@ void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, SetConsoleTextAttribute(stdout_handle, original_color_attrs); #else const char* color_code = GetPlatformColorCode(color); - if (color_code) { + if (color_code != nullptr) { out << FormatString("\033[0;3%sm", color_code); } out << FormatString(fmt, args) << "\033[m"; @@ -195,7 +195,7 @@ bool IsColorTerminal() { bool term_supports_color = false; for (const char* candidate : SUPPORTED_TERM_VALUES) { - if (term && 0 == strcmp(term, candidate)) { + if ((term != nullptr) && 0 == strcmp(term, candidate)) { term_supports_color = true; break; } diff --git a/src/commandlineflags.cc b/src/commandlineflags.cc index 5cff92558c..3ab280a028 100644 --- a/src/commandlineflags.cc +++ b/src/commandlineflags.cc @@ -109,7 +109,7 @@ bool ParseKvPairs(const std::string& src_text, const char* str, // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "BENCHMARK_FOO" in the open-source version. -static std::string FlagToEnvVar(const char* flag) { +std::string FlagToEnvVar(const char* flag) { const std::string flag_str(flag); std::string env_var; diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 2cdd995dd8..0bb9f27fbf 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -63,7 +63,7 @@ void ConsoleReporter::PrintHeader(const Run& run) { FormatString("%-*s %13s %15s %12s", static_cast(name_field_width_), "Benchmark", "Time", "CPU", "Iterations"); if (!run.counters.empty()) { - if (output_options_ & OO_Tabular) { + if ((output_options_ & OO_Tabular) != 0) { for (auto const& c : run.counters) { str += FormatString(" %10s", c.first.c_str()); } @@ -83,7 +83,7 @@ void ConsoleReporter::ReportRuns(const std::vector& reports) { bool print_header = !printed_header_; // --- or if the format is tabular and this run // has different fields from the prev header - print_header |= (output_options_ & OO_Tabular) && + print_header |= ((output_options_ & OO_Tabular) != 0) && (!internal::SameNames(run.counters, prev_counters_)); if (print_header) { printed_header_ = true; @@ -97,8 +97,8 @@ void ConsoleReporter::ReportRuns(const std::vector& reports) { } } -static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt, - ...) { +static void IgnoreColorPrint(std::ostream& out, LogColor /*unused*/, + const char* fmt, ...) { va_list args; va_start(args, fmt); out << FormatString(fmt, args); @@ -131,7 +131,7 @@ BENCHMARK_EXPORT void ConsoleReporter::PrintRunData(const Run& result) { typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...); auto& Out = GetOutputStream(); - PrinterFn* printer = (output_options_ & OO_Color) + PrinterFn* printer = (output_options_ & OO_Color) != 0 ? static_cast(ColorPrintf) : IgnoreColorPrint; auto name_color = @@ -144,7 +144,8 @@ void ConsoleReporter::PrintRunData(const Run& result) { result.skip_message.c_str()); printer(Out, COLOR_DEFAULT, "\n"); return; - } else if (internal::SkippedWithMessage == result.skipped) { + } + if (internal::SkippedWithMessage == result.skipped) { printer(Out, COLOR_WHITE, "SKIPPED: \'%s\'", result.skip_message.c_str()); printer(Out, COLOR_DEFAULT, "\n"); return; @@ -178,9 +179,9 @@ void ConsoleReporter::PrintRunData(const Run& result) { printer(Out, COLOR_CYAN, "%10lld", result.iterations); } - for (auto& c : result.counters) { + for (const auto& c : result.counters) { const std::size_t cNameLen = - std::max(std::string::size_type(10), c.first.length()); + std::max(static_cast(10), c.first.length()); std::string s; const char* unit = ""; if (result.run_type == Run::RT_Aggregate && @@ -189,11 +190,11 @@ void ConsoleReporter::PrintRunData(const Run& result) { unit = "%"; } else { s = HumanReadableNumber(c.second.value, c.second.oneK); - if (c.second.flags & Counter::kIsRate) { - unit = (c.second.flags & Counter::kInvert) ? "s" : "/s"; + if ((c.second.flags & Counter::kIsRate) != 0) { + unit = (c.second.flags & Counter::kInvert) != 0 ? "s" : "/s"; } } - if (output_options_ & OO_Tabular) { + if ((output_options_ & OO_Tabular) != 0) { printer(Out, COLOR_DEFAULT, " %*s%s", cNameLen - strlen(unit), s.c_str(), unit); } else { diff --git a/src/counter.cc b/src/counter.cc index e0d320dcc4..a76bf76770 100644 --- a/src/counter.cc +++ b/src/counter.cc @@ -20,20 +20,20 @@ namespace internal { double Finish(Counter const& c, IterationCount iterations, double cpu_time, double num_threads) { double v = c.value; - if (c.flags & Counter::kIsRate) { + if ((c.flags & Counter::kIsRate) != 0) { v /= cpu_time; } - if (c.flags & Counter::kAvgThreads) { + if ((c.flags & Counter::kAvgThreads) != 0) { v /= num_threads; } - if (c.flags & Counter::kIsIterationInvariant) { + if ((c.flags & Counter::kIsIterationInvariant) != 0) { v *= static_cast(iterations); } - if (c.flags & Counter::kAvgIterations) { + if ((c.flags & Counter::kAvgIterations) != 0) { v /= static_cast(iterations); } - if (c.flags & Counter::kInvert) { // Invert is *always* last. + if ((c.flags & Counter::kInvert) != 0) { // Invert is *always* last. v = 1.0 / v; } return v; diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 82a391ef30..3ee434b43c 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -115,7 +115,7 @@ BENCHMARK_EXPORT void CSVReporter::PrintRunData(const Run& run) { std::ostream& Out = GetOutputStream(); Out << CsvEscape(run.benchmark_name()) << ","; - if (run.skipped) { + if (run.skipped != 0u) { Out << std::string(elements.size() - 3, ','); Out << std::boolalpha << (internal::SkippedWithError == run.skipped) << ","; Out << CsvEscape(run.skip_message) << "\n"; diff --git a/src/json_reporter.cc b/src/json_reporter.cc index 2ab51d287d..af0f34e0f8 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -85,6 +85,10 @@ std::string FormatKV(std::string const& key, int64_t value) { return ss.str(); } +std::string FormatKV(std::string const& key, int value) { + return FormatKV(key, static_cast(value)); +} + std::string FormatKV(std::string const& key, double value) { std::stringstream ss; ss << '"' << StrEscape(key) << "\": "; @@ -122,7 +126,7 @@ bool JSONReporter::ReportContext(const Context& context) { out << indent << FormatKV("host_name", context.sys_info.name) << ",\n"; - if (Context::executable_name) { + if (Context::executable_name != nullptr) { out << indent << FormatKV("executable", Context::executable_name) << ",\n"; } @@ -136,7 +140,7 @@ bool JSONReporter::ReportContext(const Context& context) { if (CPUInfo::Scaling::UNKNOWN != info.scaling) { out << indent << FormatKV("cpu_scaling_enabled", - info.scaling == CPUInfo::Scaling::ENABLED ? true : false) + info.scaling == CPUInfo::Scaling::ENABLED) << ",\n"; } @@ -144,7 +148,7 @@ bool JSONReporter::ReportContext(const Context& context) { indent = std::string(6, ' '); std::string cache_indent(8, ' '); for (size_t i = 0; i < info.caches.size(); ++i) { - auto& CI = info.caches[i]; + const auto& CI = info.caches[i]; out << indent << "{\n"; out << cache_indent << FormatKV("type", CI.type) << ",\n"; out << cache_indent << FormatKV("level", static_cast(CI.level)) @@ -183,7 +187,7 @@ bool JSONReporter::ReportContext(const Context& context) { out << ",\n"; // NOTE: our json schema is not strictly tied to the library version! - out << indent << FormatKV("json_schema_version", int64_t(1)); + out << indent << FormatKV("json_schema_version", 1); std::map* global_context = internal::GetGlobalContext(); @@ -298,11 +302,11 @@ void JSONReporter::PrintRunData(Run const& run) { out << indent << FormatKV("rms", run.GetAdjustedCPUTime()); } - for (auto& c : run.counters) { + for (const auto& c : run.counters) { out << ",\n" << indent << FormatKV(c.first, c.second); } - if (run.memory_result) { + if (run.memory_result != nullptr) { const MemoryManager::Result memory_result = *run.memory_result; out << ",\n" << indent << FormatKV("allocs_per_iter", run.allocs_per_iter); out << ",\n" diff --git a/src/reporter.cc b/src/reporter.cc index 263e969d8b..1f19ff9c05 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -42,17 +42,18 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, Out << LocalDateTimeString() << "\n"; #endif - if (context.executable_name) { - Out << "Running " << context.executable_name << "\n"; + if (benchmark::BenchmarkReporter::Context::executable_name != nullptr) { + Out << "Running " << benchmark::BenchmarkReporter::Context::executable_name + << "\n"; } const CPUInfo &info = context.cpu_info; Out << "Run on (" << info.num_cpus << " X " << (info.cycles_per_second / 1000000.0) << " MHz CPU " << ((info.num_cpus > 1) ? "s" : "") << ")\n"; - if (info.caches.size() != 0) { + if (!info.caches.empty()) { Out << "CPU Caches:\n"; - for (auto &CInfo : info.caches) { + for (const auto &CInfo : info.caches) { Out << " L" << CInfo.level << " " << CInfo.type << " " << (CInfo.size / 1024) << " KiB"; if (CInfo.num_sharing != 0) { diff --git a/src/statistics.cc b/src/statistics.cc index 12eb5602d9..fdf76c9c94 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -153,7 +153,7 @@ std::vector ComputeStats( for (Run const& run : reports) { BM_CHECK_EQ(reports[0].benchmark_name(), run.benchmark_name()); BM_CHECK_EQ(run_iterations, run.iterations); - if (run.skipped) { + if (run.skipped != 0u) { continue; } real_accumulated_time_stat.emplace_back(run.real_accumulated_time); @@ -176,7 +176,7 @@ std::vector ComputeStats( } const double iteration_rescale_factor = - double(reports.size()) / double(run_iterations); + static_cast(reports.size()) / static_cast(run_iterations); for (const auto& Stat : *reports[0].statistics) { // Get the data from the accumulator to BenchmarkReporter::Run's. diff --git a/src/string_util.cc b/src/string_util.cc index e50812eaff..420de4cf25 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -29,7 +29,7 @@ static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits), static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits), "Small SI and Big SI unit arrays must be the same size"); -static const int64_t kUnitsSize = arraysize(kBigSIUnits); +const int64_t kUnitsSize = arraysize(kBigSIUnits); void ToExponentAndMantissa(double val, int precision, double one_k, std::string* mantissa, int64_t* exponent) { diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 89518a93bf..b57dd89fcf 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -76,7 +76,6 @@ #include "benchmark/benchmark.h" #include "check.h" #include "cycleclock.h" -#include "internal_macros.h" #include "log.h" #include "string_util.h" #include "timers.h" @@ -121,7 +120,7 @@ struct ValueUnion { explicit ValueUnion(std::size_t buff_size) : size(sizeof(DataT) + buff_size), - buff(::new (std::malloc(size)) DataT(), &std::free) {} + buff(::new(std::malloc(size)) DataT(), &std::free) {} ValueUnion(ValueUnion&& other) = default; diff --git a/src/timers.cc b/src/timers.cc index adaab3ab56..f8d9560ed1 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -107,7 +107,7 @@ double MakeTime(struct timespec const& ts) { } #endif -BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) { +BENCHMARK_NORETURN void DiagnoseAndExit(const char* msg) { std::cerr << "ERROR: " << msg << '\n'; std::flush(std::cerr); std::exit(EXIT_FAILURE); diff --git a/test/basic_test.cc b/test/basic_test.cc index c25bec7ddd..c3ac4946d8 100644 --- a/test/basic_test.cc +++ b/test/basic_test.cc @@ -5,7 +5,8 @@ void BM_empty(benchmark::State& state) { for (auto _ : state) { - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } } diff --git a/test/benchmark_random_interleaving_gtest.cc b/test/benchmark_random_interleaving_gtest.cc index 7f2086750d..ae3fe465b8 100644 --- a/test/benchmark_random_interleaving_gtest.cc +++ b/test/benchmark_random_interleaving_gtest.cc @@ -48,7 +48,7 @@ class BenchmarkTest : public testing::Test { static void TeardownHook(int /* num_threads */) { queue->push("Teardown"); } - void Execute(const std::string& pattern) { + static void Execute(const std::string& pattern) { queue->Clear(); std::unique_ptr reporter(new NullReporter()); diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index 6c3cc2e58f..84ddc69a16 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -80,7 +80,7 @@ int fixture_setup = 0; class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture { public: - void SetUp(const ::benchmark::State&) override { + void SetUp(const ::benchmark::State& /*unused*/) override { fixture_interaction::fixture_setup++; } @@ -92,7 +92,7 @@ BENCHMARK_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)(benchmark::State& st) { } } -static void DoSetupWithFixture(const benchmark::State&) { +static void DoSetupWithFixture(const benchmark::State& /*unused*/) { fixture_interaction::setup++; } @@ -110,7 +110,7 @@ namespace repetitions { int setup = 0; } -static void DoSetupWithRepetitions(const benchmark::State&) { +static void DoSetupWithRepetitions(const benchmark::State& /*unused*/) { repetitions::setup++; } static void BM_WithRep(benchmark::State& state) { diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index 69b21221c6..61de28620a 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -46,16 +46,17 @@ void try_invalid_pause_resume(benchmark::State& state) { void BM_diagnostic_test(benchmark::State& state) { static bool called_once = false; - if (called_once == false) { + if (!called_once) { try_invalid_pause_resume(state); } for (auto _ : state) { - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } - if (called_once == false) { + if (!called_once) { try_invalid_pause_resume(state); } @@ -66,16 +67,17 @@ BENCHMARK(BM_diagnostic_test); void BM_diagnostic_test_keep_running(benchmark::State& state) { static bool called_once = false; - if (called_once == false) { + if (!called_once) { try_invalid_pause_resume(state); } while (state.KeepRunning()) { - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } - if (called_once == false) { + if (!called_once) { try_invalid_pause_resume(state); } diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc index 04ec9386a3..75db934b97 100644 --- a/test/donotoptimize_test.cc +++ b/test/donotoptimize_test.cc @@ -4,7 +4,7 @@ namespace { #if defined(__GNUC__) -std::int64_t double_up(const std::int64_t x) __attribute__((const)); +std::int64_t double_up(std::int64_t x) __attribute__((const)); #endif std::int64_t double_up(const std::int64_t x) { return x * 2; } } // namespace @@ -26,7 +26,7 @@ struct BitRef { BitRef(int i, unsigned char& b) : index(i), byte(b) {} }; -int main(int, char*[]) { +int main(int /*unused*/, char* /*unused*/[]) { // this test verifies compilation of DoNotOptimize() for some types char buffer1[1] = ""; diff --git a/test/link_main_test.cc b/test/link_main_test.cc index 131937eebc..b0a37c06e1 100644 --- a/test/link_main_test.cc +++ b/test/link_main_test.cc @@ -2,7 +2,8 @@ void BM_empty(benchmark::State& state) { for (auto _ : state) { - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } } diff --git a/test/map_test.cc b/test/map_test.cc index 0fdba7c87c..216ed0334a 100644 --- a/test/map_test.cc +++ b/test/map_test.cc @@ -39,7 +39,7 @@ class MapFixture : public ::benchmark::Fixture { m = ConstructRandomMap(static_cast(st.range(0))); } - void TearDown(const ::benchmark::State&) override { m.clear(); } + void TearDown(const ::benchmark::State& /*unused*/) override { m.clear(); } std::map m; }; diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index 4df674d586..ebb72b0341 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -14,7 +14,8 @@ class TestMemoryManager : public benchmark::MemoryManager { void BM_empty(benchmark::State& state) { for (auto _ : state) { - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } } diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index 73ce2bcfd6..a0898be90c 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -98,7 +98,7 @@ void CheckCase(std::stringstream& remaining_output, TestCase const& TC, std::string first_line; bool on_first = true; std::string line; - while (remaining_output.eof() == false) { + while (!remaining_output.eof()) { BM_CHECK(remaining_output.good()); std::getline(remaining_output, line); if (on_first) { @@ -149,7 +149,7 @@ class TestReporter : public benchmark::BenchmarkReporter { bool ReportContext(const Context& context) override { bool last_ret = false; bool first = true; - for (auto rep : reporters_) { + for (auto* rep : reporters_) { bool new_ret = rep->ReportContext(context); BM_CHECK(first || new_ret == last_ret) << "Reports return different values for ReportContext"; @@ -161,12 +161,12 @@ class TestReporter : public benchmark::BenchmarkReporter { } void ReportRuns(const std::vector& report) override { - for (auto rep : reporters_) { + for (auto* rep : reporters_) { rep->ReportRuns(report); } } void Finalize() override { - for (auto rep : reporters_) { + for (auto* rep : reporters_) { rep->Finalize(); } } @@ -206,7 +206,7 @@ class ResultsChecker { void SetHeader_(const std::string& csv_header); void SetValues_(const std::string& entry_csv_line); - std::vector SplitCsv_(const std::string& line); + std::vector SplitCsv_(const std::string& line) const; }; // store the static ResultsChecker in a function to prevent initialization @@ -239,7 +239,7 @@ void ResultsChecker::CheckResults(std::stringstream& output) { // now go over every line and publish it to the ResultsChecker std::string line; bool on_first = true; - while (output.eof() == false) { + while (!output.eof()) { BM_CHECK(output.good()); std::getline(output, line); if (on_first) { @@ -287,7 +287,8 @@ void ResultsChecker::SetValues_(const std::string& entry_csv_line) { } // a quick'n'dirty csv splitter (eliminating quotes) -std::vector ResultsChecker::SplitCsv_(const std::string& line) { +std::vector ResultsChecker::SplitCsv_( + const std::string& line) const { std::vector out; if (line.empty()) { return out; @@ -295,8 +296,10 @@ std::vector ResultsChecker::SplitCsv_(const std::string& line) { if (!field_names.empty()) { out.reserve(field_names.size()); } - size_t prev = 0, pos = line.find_first_of(','), curr = pos; - while (pos != line.npos) { + size_t prev = 0; + size_t pos = line.find_first_of(','); + size_t curr = pos; + while (pos != std::string::npos) { BM_CHECK(curr > 0); if (line[prev] == '"') { ++prev; @@ -330,7 +333,7 @@ size_t AddChecker(const std::string& bm_name, const ResultsCheckFn& fn) { int Results::NumThreads() const { auto pos = name.find("/threads:"); - if (pos == name.npos) { + if (pos == std::string::npos) { return 1; } auto end = name.find('/', pos + 9); @@ -348,7 +351,7 @@ double Results::GetTime(BenchmarkTime which) const { BM_CHECK(which == kCpuTime || which == kRealTime); const char* which_str = which == kCpuTime ? "cpu_time" : "real_time"; double val = GetAs(which_str); - auto unit = Get("time_unit"); + const auto* unit = Get("time_unit"); BM_CHECK(unit); if (*unit == "ns") { return val * 1.e-9; @@ -517,7 +520,7 @@ static std::string GetTempFileName() { // create the same file at the same time. However, it still introduces races // similar to tmpnam. int retries = 3; - while (--retries) { + while (--retries != 0) { std::string name = GetRandomFileName(); if (!FileExists(name)) { return name; @@ -539,7 +542,7 @@ std::string GetFileReporterOutput(int argc, char* argv[]) { tmp += tmp_file_name; new_argv.emplace_back(const_cast(tmp.c_str())); - argc = int(new_argv.size()); + argc = static_cast(new_argv.size()); benchmark::Initialize(&argc, new_argv.data()); benchmark::RunSpecifiedBenchmarks(); diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index e2f911e184..9cfae69698 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -164,7 +164,7 @@ void RunTestOne() { // benchmarks. // Also test that new benchmarks can be registered and ran afterwards. void RunTestTwo() { - assert(ExpectedResults.size() != 0 && + assert(!ExpectedResults.empty() && "must have at least one registered benchmark"); ExpectedResults.clear(); benchmark::ClearRegisteredBenchmarks(); diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 7867165d1f..ce6ddf2998 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -96,7 +96,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_basic\",%csv_report$"}}); void BM_bytes_per_second(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } state.SetBytesProcessed(1); @@ -128,7 +129,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_bytes_per_second\",%csv_bytes_report$"}}); void BM_items_per_second(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } state.SetItemsProcessed(1); @@ -409,7 +411,8 @@ ADD_CASES(TC_ConsoleOut, {{"^BM_BigArgs/1073741824 %console_report$"}, void BM_Complexity_O1(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } state.SetComplexityN(state.range(0)); diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 040bd4219c..a50cc45721 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -97,11 +97,11 @@ BENCHMARK(BM_error_before_running_range_for); ADD_CASES("BM_error_before_running_range_for", {{"", true, "error message"}}); void BM_error_during_running(benchmark::State& state) { - int first_iter = true; + int first_iter = 1; while (state.KeepRunning()) { if (state.range(0) == 1 && state.thread_index() <= (state.threads() / 2)) { assert(first_iter); - first_iter = false; + first_iter = 0; state.SkipWithError("error message"); } else { state.PauseTiming(); @@ -143,7 +143,8 @@ ADD_CASES("BM_error_during_running_ranged_for", void BM_error_after_running(benchmark::State& state) { for (auto _ : state) { - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } if (state.thread_index() <= (state.threads() / 2)) { diff --git a/test/string_util_gtest.cc b/test/string_util_gtest.cc index 67b4bc0c24..5a9a09e19b 100644 --- a/test/string_util_gtest.cc +++ b/test/string_util_gtest.cc @@ -13,18 +13,18 @@ namespace { TEST(StringUtilTest, stoul) { { size_t pos = 0; - EXPECT_EQ(0ul, benchmark::stoul("0", &pos)); - EXPECT_EQ(1ul, pos); + EXPECT_EQ(0UL, benchmark::stoul("0", &pos)); + EXPECT_EQ(1UL, pos); } { size_t pos = 0; - EXPECT_EQ(7ul, benchmark::stoul("7", &pos)); - EXPECT_EQ(1ul, pos); + EXPECT_EQ(7UL, benchmark::stoul("7", &pos)); + EXPECT_EQ(1UL, pos); } { size_t pos = 0; - EXPECT_EQ(135ul, benchmark::stoul("135", &pos)); - EXPECT_EQ(3ul, pos); + EXPECT_EQ(135UL, benchmark::stoul("135", &pos)); + EXPECT_EQ(3UL, pos); } #if ULONG_MAX == 0xFFFFFFFFul { @@ -35,35 +35,35 @@ TEST(StringUtilTest, stoul) { #elif ULONG_MAX == 0xFFFFFFFFFFFFFFFFul { size_t pos = 0; - EXPECT_EQ(0xFFFFFFFFFFFFFFFFul, + EXPECT_EQ(0xFFFFFFFFFFFFFFFFUL, benchmark::stoul("18446744073709551615", &pos)); - EXPECT_EQ(20ul, pos); + EXPECT_EQ(20UL, pos); } #endif { size_t pos = 0; - EXPECT_EQ(10ul, benchmark::stoul("1010", &pos, 2)); - EXPECT_EQ(4ul, pos); + EXPECT_EQ(10UL, benchmark::stoul("1010", &pos, 2)); + EXPECT_EQ(4UL, pos); } { size_t pos = 0; - EXPECT_EQ(520ul, benchmark::stoul("1010", &pos, 8)); - EXPECT_EQ(4ul, pos); + EXPECT_EQ(520UL, benchmark::stoul("1010", &pos, 8)); + EXPECT_EQ(4UL, pos); } { size_t pos = 0; - EXPECT_EQ(1010ul, benchmark::stoul("1010", &pos, 10)); - EXPECT_EQ(4ul, pos); + EXPECT_EQ(1010UL, benchmark::stoul("1010", &pos, 10)); + EXPECT_EQ(4UL, pos); } { size_t pos = 0; - EXPECT_EQ(4112ul, benchmark::stoul("1010", &pos, 16)); - EXPECT_EQ(4ul, pos); + EXPECT_EQ(4112UL, benchmark::stoul("1010", &pos, 16)); + EXPECT_EQ(4UL, pos); } { size_t pos = 0; - EXPECT_EQ(0xBEEFul, benchmark::stoul("BEEF", &pos, 16)); - EXPECT_EQ(4ul, pos); + EXPECT_EQ(0xBEEFUL, benchmark::stoul("BEEF", &pos, 16)); + EXPECT_EQ(4UL, pos); } #ifndef BENCHMARK_HAS_NO_EXCEPTIONS { @@ -73,83 +73,87 @@ TEST(StringUtilTest, stoul) { #endif } -TEST(StringUtilTest, stoi){{size_t pos = 0; -EXPECT_EQ(0, benchmark::stoi("0", &pos)); -EXPECT_EQ(1ul, pos); -} // namespace -{ - size_t pos = 0; - EXPECT_EQ(-17, benchmark::stoi("-17", &pos)); - EXPECT_EQ(3ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(1357, benchmark::stoi("1357", &pos)); - EXPECT_EQ(4ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(10, benchmark::stoi("1010", &pos, 2)); - EXPECT_EQ(4ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(520, benchmark::stoi("1010", &pos, 8)); - EXPECT_EQ(4ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(1010, benchmark::stoi("1010", &pos, 10)); - EXPECT_EQ(4ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(4112, benchmark::stoi("1010", &pos, 16)); - EXPECT_EQ(4ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(0xBEEF, benchmark::stoi("BEEF", &pos, 16)); - EXPECT_EQ(4ul, pos); -} +TEST(StringUtilTest, stoi) { + { + size_t pos = 0; + EXPECT_EQ(0, benchmark::stoi("0", &pos)); + EXPECT_EQ(1UL, pos); + } // namespace + { + size_t pos = 0; + EXPECT_EQ(-17, benchmark::stoi("-17", &pos)); + EXPECT_EQ(3UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1357, benchmark::stoi("1357", &pos)); + EXPECT_EQ(4UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(10, benchmark::stoi("1010", &pos, 2)); + EXPECT_EQ(4UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(520, benchmark::stoi("1010", &pos, 8)); + EXPECT_EQ(4UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1010, benchmark::stoi("1010", &pos, 10)); + EXPECT_EQ(4UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(4112, benchmark::stoi("1010", &pos, 16)); + EXPECT_EQ(4UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(0xBEEF, benchmark::stoi("BEEF", &pos, 16)); + EXPECT_EQ(4UL, pos); + } #ifndef BENCHMARK_HAS_NO_EXCEPTIONS -{ - ASSERT_THROW(std::ignore = benchmark::stoi("this is a test"), - std::invalid_argument); -} + { + ASSERT_THROW(std::ignore = benchmark::stoi("this is a test"), + std::invalid_argument); + } #endif } -TEST(StringUtilTest, stod){{size_t pos = 0; -EXPECT_EQ(0.0, benchmark::stod("0", &pos)); -EXPECT_EQ(1ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(-84.0, benchmark::stod("-84", &pos)); - EXPECT_EQ(3ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(1234.0, benchmark::stod("1234", &pos)); - EXPECT_EQ(4ul, pos); -} -{ - size_t pos = 0; - EXPECT_EQ(1.5, benchmark::stod("1.5", &pos)); - EXPECT_EQ(3ul, pos); -} -{ - size_t pos = 0; - /* Note: exactly representable as double */ - EXPECT_EQ(-1.25e+9, benchmark::stod("-1.25e+9", &pos)); - EXPECT_EQ(8ul, pos); -} +TEST(StringUtilTest, stod) { + { + size_t pos = 0; + EXPECT_EQ(0.0, benchmark::stod("0", &pos)); + EXPECT_EQ(1UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(-84.0, benchmark::stod("-84", &pos)); + EXPECT_EQ(3UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1234.0, benchmark::stod("1234", &pos)); + EXPECT_EQ(4UL, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1.5, benchmark::stod("1.5", &pos)); + EXPECT_EQ(3UL, pos); + } + { + size_t pos = 0; + /* Note: exactly representable as double */ + EXPECT_EQ(-1.25e+9, benchmark::stod("-1.25e+9", &pos)); + EXPECT_EQ(8UL, pos); + } #ifndef BENCHMARK_HAS_NO_EXCEPTIONS -{ - ASSERT_THROW(std::ignore = benchmark::stod("this is a test"), - std::invalid_argument); -} + { + ASSERT_THROW(std::ignore = benchmark::stod("this is a test"), + std::invalid_argument); + } #endif } diff --git a/test/time_unit_gtest.cc b/test/time_unit_gtest.cc index 484ecbcfb4..21fd91b929 100644 --- a/test/time_unit_gtest.cc +++ b/test/time_unit_gtest.cc @@ -9,7 +9,7 @@ namespace { class DummyBenchmark : public Benchmark { public: DummyBenchmark() : Benchmark("dummy") {} - void Run(State&) override {} + void Run(State& /*state*/) override {} }; TEST(DefaultTimeUnitTest, TimeUnitIsNotSet) { diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index cfc1ab069c..d26120e082 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -64,7 +64,8 @@ ADD_CASES(TC_CSVOut, {{"%csv_header," void BM_Counters_Tabular(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -375,7 +376,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Tabular/repeats:2/threads:2$", void BM_CounterRates_Tabular(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index 22252acbf6..d3fd4a6eab 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -67,7 +67,8 @@ int num_calls1 = 0; void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } state.counters["foo"] = 1; @@ -119,7 +120,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec", void BM_Counters_Rate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -163,7 +165,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate); void BM_Invert(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -204,7 +207,8 @@ CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert); void BM_Counters_InvertedRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -333,7 +337,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int", void BM_Counters_AvgThreadsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -421,7 +426,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant", void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; @@ -513,7 +519,8 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations", &CheckAvgIterations); void BM_Counters_kAvgIterationsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero - auto iterations = double(state.iterations()) * double(state.iterations()); + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); benchmark::DoNotOptimize(iterations); } namespace bm = benchmark; From 657a55a0d49b7812ae657266a6faa4c57820a10b Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 17 Feb 2025 14:28:32 +0100 Subject: [PATCH 317/561] dx: Update pre-commit repos, change imports of Python / CC rules (#1937) The changes are an autofix added in Buildifier 8.0.1, designed to future-proof Bazel projects against the eventual removal of these rules from the native Bazel namespace. --- .pre-commit-config.yaml | 6 +++--- BUILD.bazel | 2 ++ bindings/python/google_benchmark/BUILD | 1 + tools/BUILD.bazel | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c16928a946..44aa3bde42 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 8.0.0 + rev: 8.0.1 hooks: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.14.1 + rev: v1.15.0 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.2 + rev: v0.9.6 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/BUILD.bazel b/BUILD.bazel index 8d91c4df85..178052c22c 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + licenses(["notice"]) COPTS = [ diff --git a/bindings/python/google_benchmark/BUILD b/bindings/python/google_benchmark/BUILD index 30e389337d..8938b3716e 100644 --- a/bindings/python/google_benchmark/BUILD +++ b/bindings/python/google_benchmark/BUILD @@ -1,4 +1,5 @@ load("@nanobind_bazel//:build_defs.bzl", "nanobind_extension", "nanobind_stubgen") +load("@rules_python//python:defs.bzl", "py_library", "py_test") py_library( name = "google_benchmark", diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 8ef6a86598..a49edb7f72 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_python//python:defs.bzl", "py_binary", "py_library") load("@tools_pip_deps//:requirements.bzl", "requirement") py_library( From afa46a38d92752627890d56248d63503da90f2cf Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 17 Feb 2025 14:44:39 +0100 Subject: [PATCH 318/561] deps: Update nanobind_bazel to v2.5.0 (#1936) No new functionality, just an update to the newest nanobind. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index d8c93905f6..d346b72074 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -38,4 +38,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "2.4.0", dev_dependency = True) +bazel_dep(name = "nanobind_bazel", version = "2.5.0", dev_dependency = True) From 57efbfb3a05e272a5f84564787a607d81a84fe5b Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 18 Feb 2025 09:59:27 +0000 Subject: [PATCH 319/561] use smart pointers (#1935) * use smart pointers * use vectors * size_t --- src/re.h | 8 +++----- test/benchmark_min_time_flag_iters_test.cc | 9 ++++----- test/benchmark_min_time_flag_time_test.cc | 13 ++++++------- test/benchmark_test.cc | 11 ++++++----- test/profiler_manager_iterations_test.cc | 9 ++++----- 5 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/re.h b/src/re.h index 9afb869bea..af4b8bb16e 100644 --- a/src/re.h +++ b/src/re.h @@ -121,15 +121,13 @@ inline bool Regex::Init(const std::string& spec, std::string* error) { if (ec != 0) { if (error) { size_t needed = regerror(ec, &re_, nullptr, 0); - char* errbuf = new char[needed]; - regerror(ec, &re_, errbuf, needed); + std::vector errbuf(needed); + regerror(ec, &re_, errbuf.data(), needed); // regerror returns the number of bytes necessary to null terminate // the string, so we move that when assigning to error. BM_CHECK_NE(needed, 0); - error->assign(errbuf, needed - 1); - - delete[] errbuf; + error->assign(errbuf.data(), needed - 1); } return false; diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index 60d512d0ea..a5964f10b3 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -46,13 +46,13 @@ BENCHMARK(BM_MyBench); int main(int argc, char** argv) { // Make a fake argv and append the new --benchmark_min_time= to it. int fake_argc = argc + 1; - const char** fake_argv = new const char*[static_cast(fake_argc)]; - for (int i = 0; i < argc; ++i) { + std::vector fake_argv(static_cast(fake_argc)); + for (size_t i = 0; i < static_cast(argc); ++i) { fake_argv[i] = argv[i]; } - fake_argv[argc] = "--benchmark_min_time=4x"; + fake_argv[static_cast(argc)] = "--benchmark_min_time=4x"; - benchmark::Initialize(&fake_argc, const_cast(fake_argv)); + benchmark::Initialize(&fake_argc, const_cast(fake_argv.data())); TestReporter test_reporter; const size_t returned_count = @@ -63,6 +63,5 @@ int main(int argc, char** argv) { const std::vector iters = test_reporter.GetIters(); assert(!iters.empty() && iters[0] == 4); - delete[] fake_argv; return 0; } diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index 95a83f5441..0a136fa088 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -71,9 +71,9 @@ BENCHMARK(BM_MyBench); int main(int argc, char** argv) { // Make a fake argv and append the new --benchmark_min_time= to it. int fake_argc = argc + 1; - const char** fake_argv = new const char*[static_cast(fake_argc)]; + std::vector fake_argv(static_cast(fake_argc)); - for (int i = 0; i < argc; ++i) { + for (size_t i = 0; i < static_cast(argc); ++i) { fake_argv[i] = argv[i]; } @@ -81,12 +81,11 @@ int main(int argc, char** argv) { const char* with_suffix = "--benchmark_min_time=4.0s"; double expected = 4.0; - fake_argv[argc] = no_suffix; - DoTestHelper(&fake_argc, fake_argv, expected); + fake_argv[static_cast(argc)] = no_suffix; + DoTestHelper(&fake_argc, fake_argv.data(), expected); - fake_argv[argc] = with_suffix; - DoTestHelper(&fake_argc, fake_argv, expected); + fake_argv[static_cast(argc)] = with_suffix; + DoTestHelper(&fake_argc, fake_argv.data(), expected); - delete[] fake_argv; return 0; } diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index b02274e40c..97fca3c7c6 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,7 @@ std::set ConstructRandomSet(int64_t size) { } std::mutex test_vector_mu; -std::vector* test_vector = nullptr; +std::optional> test_vector; } // end namespace @@ -146,7 +147,7 @@ BENCHMARK(BM_StringCompare)->Range(1, 1 << 20); static void BM_SetupTeardown(benchmark::State& state) { if (state.thread_index() == 0) { // No need to lock test_vector_mu here as this is running single-threaded. - test_vector = new std::vector(); + test_vector = std::vector(); } int i = 0; for (auto _ : state) { @@ -159,7 +160,7 @@ static void BM_SetupTeardown(benchmark::State& state) { ++i; } if (state.thread_index() == 0) { - delete test_vector; + test_vector.reset(); } } BENCHMARK(BM_SetupTeardown)->ThreadPerCpu(); @@ -181,7 +182,7 @@ static void BM_ParallelMemset(benchmark::State& state) { int to = from + thread_size; if (state.thread_index() == 0) { - test_vector = new std::vector(static_cast(size)); + test_vector = std::vector(static_cast(size)); } for (auto _ : state) { @@ -193,7 +194,7 @@ static void BM_ParallelMemset(benchmark::State& state) { } if (state.thread_index() == 0) { - delete test_vector; + test_vector.reset(); } } BENCHMARK(BM_ParallelMemset)->Arg(10 << 20)->ThreadRange(1, 4); diff --git a/test/profiler_manager_iterations_test.cc b/test/profiler_manager_iterations_test.cc index 6b475f7888..407d33b994 100644 --- a/test/profiler_manager_iterations_test.cc +++ b/test/profiler_manager_iterations_test.cc @@ -38,16 +38,16 @@ int main(int argc, char** argv) { // Make a fake argv and append the new --benchmark_profiler_iterations= // to it. int fake_argc = argc + 1; - const char** fake_argv = new const char*[static_cast(fake_argc)]; - for (int i = 0; i < argc; ++i) { + std::vector fake_argv(static_cast(fake_argc)); + for (size_t i = 0; i < static_cast(argc); ++i) { fake_argv[i] = argv[i]; } - fake_argv[argc] = "--benchmark_min_time=4x"; + fake_argv[static_cast(argc)] = "--benchmark_min_time=4x"; std::unique_ptr pm(new TestProfilerManager()); benchmark::RegisterProfilerManager(pm.get()); - benchmark::Initialize(&fake_argc, const_cast(fake_argv)); + benchmark::Initialize(&fake_argc, const_cast(fake_argv.data())); NullReporter null_reporter; const size_t returned_count = @@ -58,6 +58,5 @@ int main(int argc, char** argv) { assert(end_profiler_iteration_count == 4); benchmark::RegisterProfilerManager(nullptr); - delete[] fake_argv; return 0; } From 951429282a91a4047f52f707edcb8ae1c45bcf43 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 18 Feb 2025 10:07:57 +0000 Subject: [PATCH 320/561] [clang-tidy] resolve some global clang-tidy issues (#1933) * [clang-tidy] resolve some global clang-tidy issues * more nolint and some global fixes --- src/benchmark.cc | 6 +++- src/check.cc | 5 ++- src/commandlineflags.h | 4 +++ src/statistics.cc | 8 ++--- test/benchmark_random_interleaving_gtest.cc | 3 +- test/benchmark_setup_teardown_test.cc | 6 ++++ test/benchmark_test.cc | 5 ++- test/complexity_test.cc | 34 +++++++++++---------- test/output_test.h | 8 +++-- test/register_benchmark_test.cc | 7 +++-- test/reporter_output_test.cc | 2 +- test/skip_with_error_test.cc | 3 +- 12 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index a1f71b7186..925a38ff22 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -150,13 +150,17 @@ BM_DEFINE_int32(v, 0); namespace internal { +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) std::map* global_context = nullptr; BENCHMARK_EXPORT std::map*& GetGlobalContext() { return global_context; } -static void const volatile* volatile global_force_escape_pointer; +namespace { +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +void const volatile* volatile global_force_escape_pointer; +} // namespace // FIXME: Verify if LTO still messes this up? void UseCharPointer(char const volatile* const v) { diff --git a/src/check.cc b/src/check.cc index 5f7526e08d..3e2a40b4bd 100644 --- a/src/check.cc +++ b/src/check.cc @@ -3,7 +3,10 @@ namespace benchmark { namespace internal { -static AbortHandlerT* handler = &std::abort; +namespace { +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +AbortHandlerT* handler = &std::abort; +} // namespace BENCHMARK_EXPORT AbortHandlerT*& GetAbortHandler() { return handler; } diff --git a/src/commandlineflags.h b/src/commandlineflags.h index 7882628975..5f9ebf1d56 100644 --- a/src/commandlineflags.h +++ b/src/commandlineflags.h @@ -11,14 +11,17 @@ #define FLAG(name) FLAGS_##name // Macros for declaring flags. +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) #define BM_DECLARE_bool(name) BENCHMARK_EXPORT extern bool FLAG(name) #define BM_DECLARE_int32(name) BENCHMARK_EXPORT extern int32_t FLAG(name) #define BM_DECLARE_double(name) BENCHMARK_EXPORT extern double FLAG(name) #define BM_DECLARE_string(name) BENCHMARK_EXPORT extern std::string FLAG(name) #define BM_DECLARE_kvpairs(name) \ BENCHMARK_EXPORT extern std::map FLAG(name) +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) // Macros for defining flags. +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) #define BM_DEFINE_bool(name, default_val) \ BENCHMARK_EXPORT bool FLAG(name) = benchmark::BoolFromEnv(#name, default_val) #define BM_DEFINE_int32(name, default_val) \ @@ -33,6 +36,7 @@ #define BM_DEFINE_kvpairs(name, default_val) \ BENCHMARK_EXPORT std::map FLAG(name) = \ benchmark::KvPairsFromEnv(#name, default_val) +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) namespace benchmark { diff --git a/src/statistics.cc b/src/statistics.cc index fdf76c9c94..fc7450ef91 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -26,7 +26,7 @@ namespace benchmark { -auto StatisticsSum = [](const std::vector& v) { +const auto StatisticsSum = [](const std::vector& v) { return std::accumulate(v.begin(), v.end(), 0.0); }; @@ -59,12 +59,12 @@ double StatisticsMedian(const std::vector& v) { } // Return the sum of the squares of this sample set -auto SumSquares = [](const std::vector& v) { +const auto SumSquares = [](const std::vector& v) { return std::inner_product(v.begin(), v.end(), v.begin(), 0.0); }; -auto Sqr = [](const double dat) { return dat * dat; }; -auto Sqrt = [](const double dat) { +const auto Sqr = [](const double dat) { return dat * dat; }; +const auto Sqrt = [](const double dat) { // Avoid NaN due to imprecision in the calculations if (dat < 0.0) { return 0.0; diff --git a/test/benchmark_random_interleaving_gtest.cc b/test/benchmark_random_interleaving_gtest.cc index ae3fe465b8..5f3a554743 100644 --- a/test/benchmark_random_interleaving_gtest.cc +++ b/test/benchmark_random_interleaving_gtest.cc @@ -34,7 +34,8 @@ class EventQueue : public std::queue { } }; -EventQueue* queue = new EventQueue(); +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +EventQueue* const queue = new EventQueue(); class NullReporter : public BenchmarkReporter { public: diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index 84ddc69a16..bf45fd10e9 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -10,10 +10,12 @@ // Test that Setup() and Teardown() are called exactly once // for each benchmark run (single-threaded). +namespace { namespace singlethreaded { static int setup_call = 0; static int teardown_call = 0; } // namespace singlethreaded +} // namespace static void DoSetup1(const benchmark::State& state) { ++singlethreaded::setup_call; @@ -40,11 +42,13 @@ BENCHMARK(BM_with_setup) ->Teardown(DoTeardown1); // Test that Setup() and Teardown() are called once for each group of threads. +namespace { namespace concurrent { static std::atomic setup_call(0); static std::atomic teardown_call(0); static std::atomic func_call(0); } // namespace concurrent +} // namespace static void DoSetup2(const benchmark::State& state) { concurrent::setup_call.fetch_add(1, std::memory_order_acquire); @@ -71,10 +75,12 @@ BENCHMARK(BM_concurrent) ->Threads(15); // Testing interaction with Fixture::Setup/Teardown +namespace { namespace fixture_interaction { int setup = 0; int fixture_setup = 0; } // namespace fixture_interaction +} // namespace #define FIXTURE_BECHMARK_NAME MyFixture diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index 97fca3c7c6..e00f153527 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -51,8 +51,10 @@ std::set ConstructRandomSet(int64_t size) { return s; } +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) std::mutex test_vector_mu; std::optional> test_vector; +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) } // end namespace @@ -307,7 +309,8 @@ static void BM_templated_test(benchmark::State& state) { } } -static auto BM_templated_test_double = BM_templated_test>; +static const auto BM_templated_test_double = + BM_templated_test>; BENCHMARK(BM_templated_test_double); BENCHMARK_MAIN(); diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 0729d15aa7..f208cb3a0b 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -11,7 +11,7 @@ namespace { #define ADD_COMPLEXITY_CASES(...) \ - int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__) + const int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__) int AddComplexityTest(const std::string &test_name, const std::string &big_o_test_name, @@ -94,11 +94,11 @@ BENCHMARK(BM_Complexity_O1) ->UseManualTime() ->Complexity([](benchmark::IterationCount) { return 1.0; }); -const char *one_test_name = "BM_Complexity_O1/manual_time"; -const char *big_o_1_test_name = "BM_Complexity_O1/manual_time_BigO"; -const char *rms_o_1_test_name = "BM_Complexity_O1/manual_time_RMS"; -const char *enum_auto_big_o_1 = "\\([0-9]+\\)"; -const char *lambda_big_o_1 = "f\\(N\\)"; +constexpr char one_test_name[] = "BM_Complexity_O1/manual_time"; +constexpr char big_o_1_test_name[] = "BM_Complexity_O1/manual_time_BigO"; +constexpr char rms_o_1_test_name[] = "BM_Complexity_O1/manual_time_RMS"; +constexpr char enum_auto_big_o_1[] = "\\([0-9]+\\)"; +constexpr char lambda_big_o_1[] = "f\\(N\\)"; // Add enum tests ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, @@ -151,11 +151,11 @@ BENCHMARK(BM_Complexity_O_N) return static_cast(n); }); -const char *n_test_name = "BM_Complexity_O_N/manual_time"; -const char *big_o_n_test_name = "BM_Complexity_O_N/manual_time_BigO"; -const char *rms_o_n_test_name = "BM_Complexity_O_N/manual_time_RMS"; -const char *enum_auto_big_o_n = "N"; -const char *lambda_big_o_n = "f\\(N\\)"; +constexpr char n_test_name[] = "BM_Complexity_O_N/manual_time"; +constexpr char big_o_n_test_name[] = "BM_Complexity_O_N/manual_time_BigO"; +constexpr char rms_o_n_test_name[] = "BM_Complexity_O_N/manual_time_RMS"; +constexpr char enum_auto_big_o_n[] = "N"; +constexpr char lambda_big_o_n[] = "f\\(N\\)"; // Add enum tests ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name, @@ -209,11 +209,13 @@ BENCHMARK(BM_Complexity_O_N_log_N) return kLog2E * static_cast(n) * std::log(static_cast(n)); }); -const char *n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time"; -const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time_BigO"; -const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time_RMS"; -const char *enum_auto_big_o_n_lg_n = "NlgN"; -const char *lambda_big_o_n_lg_n = "f\\(N\\)"; +constexpr char n_lg_n_test_name[] = "BM_Complexity_O_N_log_N/manual_time"; +constexpr char big_o_n_lg_n_test_name[] = + "BM_Complexity_O_N_log_N/manual_time_BigO"; +constexpr char rms_o_n_lg_n_test_name[] = + "BM_Complexity_O_N_log_N/manual_time_RMS"; +constexpr char enum_auto_big_o_n_lg_n[] = "NlgN"; +constexpr char lambda_big_o_n_lg_n[] = "f\\(N\\)"; // Add enum tests ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, diff --git a/test/output_test.h b/test/output_test.h index c48cd20463..0fd557d90b 100644 --- a/test/output_test.h +++ b/test/output_test.h @@ -16,10 +16,11 @@ #define CONCAT2(x, y) x##y #define CONCAT(x, y) CONCAT2(x, y) -#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__) +#define ADD_CASES(...) \ + const int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__) #define SET_SUBSTITUTIONS(...) \ - int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__) + const int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__) enum MatchRules : uint8_t { MR_Default, // Skip non-matching lines until a match is found. @@ -80,7 +81,8 @@ std::string GetFileReporterOutput(int argc, char* argv[]); // will be the subject of a call to checker_function // checker_function: should be of type ResultsCheckFn (see below) #define CHECK_BENCHMARK_RESULTS(bm_name_pattern, checker_function) \ - size_t CONCAT(dummy, __LINE__) = AddChecker(bm_name_pattern, checker_function) + const size_t CONCAT(dummy, __LINE__) = \ + AddChecker(bm_name_pattern, checker_function) struct Results; typedef std::function ResultsCheckFn; diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index 9cfae69698..e443ab723f 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -53,11 +53,12 @@ int AddCases(std::initializer_list const& v) { #define CONCAT(x, y) CONCAT2(x, y) #define CONCAT2(x, y) x##y -#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__}) +#define ADD_CASES(...) \ + const int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__}) } // end namespace -typedef benchmark::internal::Benchmark* ReturnVal; +using ReturnVal = benchmark::internal::Benchmark const* const; //----------------------------------------------------------------------------// // Test RegisterBenchmark with no additional arguments @@ -91,7 +92,7 @@ int RegisterFromFunction() { } return 0; } -int dummy2 = RegisterFromFunction(); +const int dummy2 = RegisterFromFunction(); ADD_CASES({"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}); #endif // BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index ce6ddf2998..bd50a255b2 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -60,7 +60,7 @@ static int AddContextCases() { AddCases(TC_JSONOut, {{"\"json_schema_version\": 1$", MR_Next}}); return 0; } -int dummy_register = AddContextCases(); +const int dummy_register = AddContextCases(); ADD_CASES(TC_CSVOut, {{"%csv_header"}}); // ========================================================================= // diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index a50cc45721..769b09db5f 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -46,6 +46,7 @@ struct TestCase { } }; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) std::vector ExpectedResults; int AddCases(const std::string& base_name, @@ -59,7 +60,7 @@ int AddCases(const std::string& base_name, #define CONCAT(x, y) CONCAT2(x, y) #define CONCAT2(x, y) x##y -#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases(__VA_ARGS__) +#define ADD_CASES(...) const int CONCAT(dummy, __LINE__) = AddCases(__VA_ARGS__) } // end namespace From 8d4fdd6e6e003867045e0bb3473b5b423818e4b7 Mon Sep 17 00:00:00 2001 From: Dillon Date: Tue, 18 Feb 2025 14:57:34 -0800 Subject: [PATCH 321/561] Fix build errors on QuRT (Hexagon) (#1938) --- src/cycleclock.h | 2 +- src/sysinfo.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index 03e02f8055..3951ff3546 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -219,7 +219,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { #elif defined(__hexagon__) uint64_t pcycle; asm volatile("%0 = C15:14" : "=r"(pcycle)); - return static_cast(pcycle); + return static_cast(pcycle); #elif defined(__alpha__) // Alpha has a cycle counter, the PCC register, but it is an unsigned 32-bit // integer and thus wraps every ~4s, making using it for tick counts diff --git a/src/sysinfo.cc b/src/sysinfo.cc index b57dd89fcf..c938b360f8 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -509,7 +509,7 @@ int GetNumCPUsImpl() { if (qurt_sysenv_get_max_hw_threads(&hardware_threads) != QURT_EOK) { hardware_threads.max_hthreads = 1; } - return hardware_threads.max_hthreads; + return static_cast(hardware_threads.max_hthreads); #elif defined(BENCHMARK_HAS_SYSCTL) // *BSD, macOS int num_cpu = -1; From ff5c94d860dcffd4f4159edf79d805bcfaca3cb8 Mon Sep 17 00:00:00 2001 From: EfesX Date: Thu, 20 Feb 2025 18:16:32 +0500 Subject: [PATCH 322/561] change setup and teardown callback type (#1934) Change type of callbacks to take `std::function` --- include/benchmark/benchmark.h | 14 +- src/benchmark_api_internal.cc | 7 +- src/benchmark_api_internal.h | 5 +- src/benchmark_register.cc | 20 ++- test/CMakeLists.txt | 1 + ...benchmark_setup_teardown_cb_types_gtest.cc | 126 ++++++++++++++++++ 6 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 test/benchmark_setup_teardown_cb_types_gtest.cc diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index eec0fc58c3..14efec13a6 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -169,6 +169,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #include #include #include +#include #include #include #include @@ -303,6 +304,10 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); namespace benchmark { class BenchmarkReporter; +class State; + +// Define alias of Setup/Teardown callback function type +using callback_function = std::function; // Default number of minimum benchmark running time in seconds. const char kDefaultMinTimeStr[] = "0.5s"; @@ -1157,10 +1162,10 @@ class BENCHMARK_EXPORT Benchmark { // // The callback will be passed a State object, which includes the number // of threads, thread-index, benchmark arguments, etc. - // - // The callback must not be NULL or self-deleting. - Benchmark* Setup(void (*setup)(const benchmark::State&)); - Benchmark* Teardown(void (*teardown)(const benchmark::State&)); + Benchmark* Setup(callback_function&&); + Benchmark* Setup(const callback_function&); + Benchmark* Teardown(callback_function&&); + Benchmark* Teardown(const callback_function&); // Pass this benchmark object to *func, which can customize // the benchmark by calling various methods like Arg, Args, @@ -1309,7 +1314,6 @@ class BENCHMARK_EXPORT Benchmark { std::vector statistics_; std::vector thread_counts_; - typedef void (*callback_function)(const benchmark::State&); callback_function setup_; callback_function teardown_; diff --git a/src/benchmark_api_internal.cc b/src/benchmark_api_internal.cc index 14d4e1341d..60609d30cd 100644 --- a/src/benchmark_api_internal.cc +++ b/src/benchmark_api_internal.cc @@ -27,7 +27,9 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx, min_time_(benchmark_.min_time_), min_warmup_time_(benchmark_.min_warmup_time_), iterations_(benchmark_.iterations_), - threads_(thread_count) { + threads_(thread_count), + setup_(benchmark_.setup_), + teardown_(benchmark_.teardown_) { name_.function_name = benchmark_.name_; size_t arg_i = 0; @@ -84,9 +86,6 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx, if (!benchmark_.thread_counts_.empty()) { name_.threads = StrFormat("threads:%d", threads_); } - - setup_ = benchmark_.setup_; - teardown_ = benchmark_.teardown_; } State BenchmarkInstance::Run( diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h index 9287c4eb43..82ab71f4bc 100644 --- a/src/benchmark_api_internal.h +++ b/src/benchmark_api_internal.h @@ -68,9 +68,8 @@ class BenchmarkInstance { IterationCount iterations_; int threads_; // Number of concurrent threads to us - typedef void (*callback_function)(const benchmark::State&); - callback_function setup_ = nullptr; - callback_function teardown_ = nullptr; + callback_function setup_; + callback_function teardown_; }; bool FindBenchmarksInternal(const std::string& re, diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 28336a1644..8b94540468 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -224,9 +224,7 @@ Benchmark::Benchmark(const std::string& name) use_real_time_(false), use_manual_time_(false), complexity_(oNone), - complexity_lambda_(nullptr), - setup_(nullptr), - teardown_(nullptr) { + complexity_lambda_(nullptr) { ComputeStatistics("mean", StatisticsMean); ComputeStatistics("median", StatisticsMedian); ComputeStatistics("stddev", StatisticsStdDev); @@ -337,13 +335,25 @@ Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) { return this; } -Benchmark* Benchmark::Setup(void (*setup)(const benchmark::State&)) { +Benchmark* Benchmark::Setup(callback_function&& setup) { + BM_CHECK(setup != nullptr); + setup_ = std::forward(setup); + return this; +} + +Benchmark* Benchmark::Setup(const callback_function& setup) { BM_CHECK(setup != nullptr); setup_ = setup; return this; } -Benchmark* Benchmark::Teardown(void (*teardown)(const benchmark::State&)) { +Benchmark* Benchmark::Teardown(callback_function&& teardown) { + BM_CHECK(teardown != nullptr); + teardown_ = std::forward(teardown); + return this; +} + +Benchmark* Benchmark::Teardown(const callback_function& teardown) { BM_CHECK(teardown != nullptr); teardown_ = teardown; return this; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3686e7ee5f..07784cef6d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -232,6 +232,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS) add_gtest(time_unit_gtest) add_gtest(min_time_parse_gtest) add_gtest(profiler_manager_gtest) + add_gtest(benchmark_setup_teardown_cb_types_gtest) endif(BENCHMARK_ENABLE_GTEST_TESTS) ############################################################################### diff --git a/test/benchmark_setup_teardown_cb_types_gtest.cc b/test/benchmark_setup_teardown_cb_types_gtest.cc new file mode 100644 index 0000000000..c5a1a662a2 --- /dev/null +++ b/test/benchmark_setup_teardown_cb_types_gtest.cc @@ -0,0 +1,126 @@ +#include "benchmark/benchmark.h" +#include "gtest/gtest.h" + +using benchmark::BenchmarkReporter; +using benchmark::callback_function; +using benchmark::ClearRegisteredBenchmarks; +using benchmark::RegisterBenchmark; +using benchmark::RunSpecifiedBenchmarks; +using benchmark::State; +using benchmark::internal::Benchmark; + +static int functor_called = 0; +struct Functor { + void operator()(const benchmark::State& /*unused*/) { functor_called++; } +}; + +class NullReporter : public BenchmarkReporter { + public: + bool ReportContext(const Context& /*context*/) override { return true; } + void ReportRuns(const std::vector& /* report */) override {} +}; + +class BenchmarkTest : public testing::Test { + public: + Benchmark* bm; + NullReporter null_reporter; + + int setup_calls; + int teardown_calls; + + void SetUp() override { + setup_calls = 0; + teardown_calls = 0; + functor_called = 0; + + bm = RegisterBenchmark("BM", [](State& st) { + for (auto _ : st) { + } + }); + bm->Iterations(1); + } + + void TearDown() override { ClearRegisteredBenchmarks(); } +}; + +// Test that Setup/Teardown can correctly take a lambda expressions +TEST_F(BenchmarkTest, LambdaTestCopy) { + auto setup_lambda = [this](const State&) { setup_calls++; }; + auto teardown_lambda = [this](const State&) { teardown_calls++; }; + bm->Setup(setup_lambda); + bm->Teardown(teardown_lambda); + RunSpecifiedBenchmarks(&null_reporter); + EXPECT_EQ(setup_calls, 1); + EXPECT_EQ(teardown_calls, 1); +} + +// Test that Setup/Teardown can correctly take a lambda expressions +TEST_F(BenchmarkTest, LambdaTestMove) { + auto setup_lambda = [this](const State&) { setup_calls++; }; + auto teardown_lambda = [this](const State&) { teardown_calls++; }; + bm->Setup(std::move(setup_lambda)); + bm->Teardown(std::move(teardown_lambda)); + RunSpecifiedBenchmarks(&null_reporter); + EXPECT_EQ(setup_calls, 1); + EXPECT_EQ(teardown_calls, 1); +} + +// Test that Setup/Teardown can correctly take std::function +TEST_F(BenchmarkTest, CallbackFunctionCopy) { + callback_function setup_lambda = [this](const State&) { setup_calls++; }; + callback_function teardown_lambda = [this](const State&) { + teardown_calls++; + }; + bm->Setup(setup_lambda); + bm->Teardown(teardown_lambda); + RunSpecifiedBenchmarks(&null_reporter); + EXPECT_EQ(setup_calls, 1); + EXPECT_EQ(teardown_calls, 1); +} + +// Test that Setup/Teardown can correctly take std::function +TEST_F(BenchmarkTest, CallbackFunctionMove) { + callback_function setup_lambda = [this](const State&) { setup_calls++; }; + callback_function teardown_lambda = [this](const State&) { + teardown_calls++; + }; + bm->Setup(std::move(setup_lambda)); + bm->Teardown(std::move(teardown_lambda)); + RunSpecifiedBenchmarks(&null_reporter); + EXPECT_EQ(setup_calls, 1); + EXPECT_EQ(teardown_calls, 1); +} + +// Test that Setup/Teardown can correctly take functors +TEST_F(BenchmarkTest, FunctorCopy) { + Functor func; + bm->Setup(func); + bm->Teardown(func); + RunSpecifiedBenchmarks(&null_reporter); + EXPECT_EQ(functor_called, 2); +} + +// Test that Setup/Teardown can correctly take functors +TEST_F(BenchmarkTest, FunctorMove) { + Functor func1; + Functor func2; + bm->Setup(std::move(func1)); + bm->Teardown(std::move(func2)); + RunSpecifiedBenchmarks(&null_reporter); + EXPECT_EQ(functor_called, 2); +} + +// Test that Setup/Teardown can not take nullptr +TEST_F(BenchmarkTest, NullptrTest) { +#if GTEST_HAS_DEATH_TEST + // Tests only runnable in debug mode (when BM_CHECK is enabled). +#ifndef NDEBUG +#ifndef TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS + EXPECT_DEATH(bm->Setup(nullptr), "setup != nullptr"); + EXPECT_DEATH(bm->Teardown(nullptr), "teardown != nullptr"); +#else + GTEST_SKIP() << "Test skipped because BM_CHECK is disabled"; +#endif +#endif +#endif +} From 571c235e1e51633e8ee0995796fae1e093a700b2 Mon Sep 17 00:00:00 2001 From: Alfred Wingate Date: Wed, 5 Mar 2025 10:43:48 +0200 Subject: [PATCH 323/561] Install FindPFM.cmake for bencmarkConfig.cmake (#1942) There is no upstream PFM cmake package config file to use, so this has to be installed for the benchmark cmake package config file to work. Bug: https://bugs.gentoo.org/950573 See-Also: c2146397ac69e6589a50f6b4fc6a7355669caed5 Signed-off-by: Alfred Wingate --- cmake/Config.cmake.in | 1 + src/CMakeLists.txt | 3 +++ 2 files changed, 4 insertions(+) diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in index 3659cfa2a6..c65cdb54e3 100644 --- a/cmake/Config.cmake.in +++ b/cmake/Config.cmake.in @@ -5,6 +5,7 @@ include (CMakeFindDependencyMacro) find_dependency (Threads) if (@BENCHMARK_ENABLE_LIBPFM@) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") find_dependency (PFM) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32126c0d24..9fb305a0e4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,6 +39,9 @@ set_property( if (PFM_FOUND) target_link_libraries(benchmark PRIVATE PFM::libpfm) target_compile_definitions(benchmark PRIVATE -DHAVE_LIBPFM) + install( + FILES "${PROJECT_SOURCE_DIR}/cmake/Modules/FindPFM.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") endif() # pthread affinity, if available From 5a4c4595480334560fca0a2bdee168371853b52f Mon Sep 17 00:00:00 2001 From: EfesX Date: Wed, 12 Mar 2025 15:15:28 +0500 Subject: [PATCH 324/561] fix memory manager result bug (#1941) * fix memory manager result bug * change is_valid to memory_iterations * fix test * some fixes * fix test ...for msvc * fix test * fix test add the correct explicitly casts * fix msvc failure * some fixes * remove unnecessary include --- include/benchmark/benchmark.h | 14 +++-- src/benchmark_runner.cc | 18 +++--- src/benchmark_runner.h | 4 +- src/json_reporter.cc | 7 +-- test/CMakeLists.txt | 1 + test/memory_results_gtest.cc | 101 ++++++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 25 deletions(-) create mode 100644 test/memory_results_gtest.cc diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 14efec13a6..663953de99 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -306,6 +306,8 @@ namespace benchmark { class BenchmarkReporter; class State; +using IterationCount = int64_t; + // Define alias of Setup/Teardown callback function type using callback_function = std::function; @@ -387,14 +389,15 @@ BENCHMARK_EXPORT void SetDefaultTimeUnit(TimeUnit unit); // benchmark. class MemoryManager { public: - static const int64_t TombstoneValue; + static constexpr int64_t TombstoneValue = std::numeric_limits::max(); struct Result { Result() : num_allocs(0), max_bytes_used(0), total_allocated_bytes(TombstoneValue), - net_heap_growth(TombstoneValue) {} + net_heap_growth(TombstoneValue), + memory_iterations(0) {} // The number of allocations made in total between Start and Stop. int64_t num_allocs; @@ -410,6 +413,8 @@ class MemoryManager { // ie., total_allocated_bytes - total_deallocated_bytes. // Init'ed to TombstoneValue if metric not available. int64_t net_heap_growth; + + IterationCount memory_iterations; }; virtual ~MemoryManager() {} @@ -659,8 +664,6 @@ enum BigO { oNone, o1, oN, oNSquared, oNCubed, oLogN, oNLogN, oAuto, oLambda }; typedef int64_t ComplexityN; -typedef int64_t IterationCount; - enum StatisticUnit { kTime, kPercentage }; // BigOFunc is passed to a benchmark in order to specify the asymptotic @@ -1721,7 +1724,6 @@ class BENCHMARK_EXPORT BenchmarkReporter { complexity_n(0), report_big_o(false), report_rms(false), - memory_result(NULL), allocs_per_iter(0.0) {} std::string benchmark_name() const; @@ -1777,7 +1779,7 @@ class BENCHMARK_EXPORT BenchmarkReporter { UserCounters counters; // Memory metrics. - const MemoryManager::Result* memory_result; + MemoryManager::Result memory_result; double allocs_per_iter; }; diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index b7d3de3db5..b062c7cead 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -81,7 +81,7 @@ BenchmarkReporter::Run CreateRunReport( const benchmark::internal::BenchmarkInstance& b, const internal::ThreadManager::Result& results, IterationCount memory_iterations, - const MemoryManager::Result* memory_result, double seconds, + const MemoryManager::Result& memory_result, double seconds, int64_t repetition_index, int64_t repeats) { // Create report about this benchmark run. BenchmarkReporter::Run report; @@ -114,11 +114,10 @@ BenchmarkReporter::Run CreateRunReport( report.counters = results.counters; if (memory_iterations > 0) { - assert(memory_result != nullptr); report.memory_result = memory_result; report.allocs_per_iter = memory_iterations != 0 - ? static_cast(memory_result->num_allocs) / + ? static_cast(memory_result.num_allocs) / static_cast(memory_iterations) : 0; } @@ -426,13 +425,8 @@ void BenchmarkRunner::RunWarmUp() { } } -MemoryManager::Result* BenchmarkRunner::RunMemoryManager( +MemoryManager::Result BenchmarkRunner::RunMemoryManager( IterationCount memory_iterations) { - // TODO(vyng): Consider making BenchmarkReporter::Run::memory_result an - // optional so we don't have to own the Result here. - // Can't do it now due to cxx03. - memory_results.push_back(MemoryManager::Result()); - MemoryManager::Result* memory_result = &memory_results.back(); memory_manager->Start(); std::unique_ptr manager; manager.reset(new internal::ThreadManager(1)); @@ -443,7 +437,9 @@ MemoryManager::Result* BenchmarkRunner::RunMemoryManager( manager->WaitForAllThreads(); manager.reset(); b.Teardown(); - memory_manager->Stop(*memory_result); + MemoryManager::Result memory_result; + memory_manager->Stop(memory_result); + memory_result.memory_iterations = memory_iterations; return memory_result; } @@ -508,7 +504,7 @@ void BenchmarkRunner::DoOneRepetition() { } // Produce memory measurements if requested. - MemoryManager::Result* memory_result = nullptr; + MemoryManager::Result memory_result; IterationCount memory_iterations = 0; if (memory_manager != nullptr) { // Only run a few iterations to reduce the impact of one-time diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index 965087eb00..bc76c81e48 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -91,8 +91,6 @@ class BenchmarkRunner { std::vector pool; - std::vector memory_results; - IterationCount iters; // preserved between repetitions! // So only the first repetition has to find/calculate it, // the other repetitions will just use that precomputed iteration count. @@ -106,7 +104,7 @@ class BenchmarkRunner { }; IterationResults DoNIterations(); - MemoryManager::Result* RunMemoryManager(IterationCount memory_iterations); + MemoryManager::Result RunMemoryManager(IterationCount memory_iterations); void RunProfilerManager(IterationCount profile_iterations); diff --git a/src/json_reporter.cc b/src/json_reporter.cc index af0f34e0f8..fe34c0786f 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -306,8 +306,8 @@ void JSONReporter::PrintRunData(Run const& run) { out << ",\n" << indent << FormatKV(c.first, c.second); } - if (run.memory_result != nullptr) { - const MemoryManager::Result memory_result = *run.memory_result; + if (run.memory_result.memory_iterations > 0) { + const auto& memory_result = run.memory_result; out << ",\n" << indent << FormatKV("allocs_per_iter", run.allocs_per_iter); out << ",\n" << indent << FormatKV("max_bytes_used", memory_result.max_bytes_used); @@ -330,7 +330,4 @@ void JSONReporter::PrintRunData(Run const& run) { out << '\n'; } -const int64_t MemoryManager::TombstoneValue = - std::numeric_limits::max(); - } // end namespace benchmark diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 07784cef6d..a7e7122dd2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -233,6 +233,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS) add_gtest(min_time_parse_gtest) add_gtest(profiler_manager_gtest) add_gtest(benchmark_setup_teardown_cb_types_gtest) + add_gtest(memory_results_gtest) endif(BENCHMARK_ENABLE_GTEST_TESTS) ############################################################################### diff --git a/test/memory_results_gtest.cc b/test/memory_results_gtest.cc new file mode 100644 index 0000000000..c40df8f508 --- /dev/null +++ b/test/memory_results_gtest.cc @@ -0,0 +1,101 @@ +#include + +#include "benchmark/benchmark.h" +#include "gtest/gtest.h" + +namespace { + +using benchmark::ClearRegisteredBenchmarks; +using benchmark::ConsoleReporter; +using benchmark::MemoryManager; +using benchmark::RegisterBenchmark; +using benchmark::RunSpecifiedBenchmarks; +using benchmark::State; +using benchmark::internal::Benchmark; + +constexpr int N_REPETITIONS = 100; +constexpr int N_ITERATIONS = 1; + +int num_allocs = 0; +int max_bytes_used = 0; +int total_allocated_bytes = 0; +int net_heap_growth = 0; + +void reset() { + num_allocs = 0; + max_bytes_used = 0; + total_allocated_bytes = 0; + net_heap_growth = 0; +} +class TestMemoryManager : public MemoryManager { + void Start() override {} + void Stop(Result& result) override { + result.num_allocs = num_allocs; + result.net_heap_growth = net_heap_growth; + result.max_bytes_used = max_bytes_used; + result.total_allocated_bytes = total_allocated_bytes; + + num_allocs += 1; + max_bytes_used += 2; + net_heap_growth += 4; + total_allocated_bytes += 10; + } +}; + +class TestReporter : public ConsoleReporter { + public: + TestReporter() = default; + virtual ~TestReporter() = default; + + bool ReportContext(const Context& /*unused*/) override { return true; } + + void PrintHeader(const Run&) override {} + void PrintRunData(const Run& run) override { + if (run.repetition_index == -1) return; + if (!run.memory_result.memory_iterations) return; + + store.push_back(run.memory_result); + } + + std::vector store; +}; + +class MemoryResultsTest : public testing::Test { + public: + Benchmark* bm; + TestReporter reporter; + + void SetUp() override { + bm = RegisterBenchmark("BM", [](State& st) { + for (auto _ : st) { + } + }); + bm->Repetitions(N_REPETITIONS); + bm->Iterations(N_ITERATIONS); + reset(); + } + void TearDown() override { ClearRegisteredBenchmarks(); } +}; + +TEST_F(MemoryResultsTest, NoMMTest) { + RunSpecifiedBenchmarks(&reporter); + EXPECT_EQ(reporter.store.size(), 0); +} + +TEST_F(MemoryResultsTest, ResultsTest) { + auto mm = std::make_unique(); + RegisterMemoryManager(mm.get()); + + RunSpecifiedBenchmarks(&reporter); + EXPECT_EQ(reporter.store.size(), N_REPETITIONS); + + for (size_t i = 0; i < reporter.store.size(); i++) { + EXPECT_EQ(reporter.store[i].num_allocs, static_cast(i)); + EXPECT_EQ(reporter.store[i].max_bytes_used, static_cast(i) * 2); + EXPECT_EQ(reporter.store[i].net_heap_growth, static_cast(i) * 4); + EXPECT_EQ(reporter.store[i].total_allocated_bytes, + static_cast(i) * 10); + } +} + +} // namespace From 2bf35340755a0be14ea175f9491a429f1c3f88e7 Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Wed, 12 Mar 2025 12:22:18 +0100 Subject: [PATCH 325/561] Compilation example was wrong. Fixed standard (#1945) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c77f9b6cbe..b30e57cfd3 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ be under the build directory you created. ```bash # Example on linux after running the build steps above. Assumes the # `benchmark` and `build` directories are under the current directory. -$ g++ mybenchmark.cc -std=c++11 -isystem benchmark/include \ +$ g++ mybenchmark.cc -std=c++14 -isystem benchmark/include \ -Lbenchmark/build/src -lbenchmark -lpthread -o mybenchmark ``` From 6cd107ffadb0b8a12f5fd56048ece69dd6056f00 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 12 Mar 2025 15:29:36 +0300 Subject: [PATCH 326/561] CI: build libcxxabi against system unwind library ... because that is what the MSan is built against, and mixing them clearly causes issues. --- .github/libcxx-setup.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/libcxx-setup.sh b/.github/libcxx-setup.sh index eacc982714..1bd972fbca 100755 --- a/.github/libcxx-setup.sh +++ b/.github/libcxx-setup.sh @@ -19,8 +19,9 @@ cmake -DCMAKE_C_COMPILER=${CC} \ -DLIBCXX_ABI_UNSTABLE=OFF \ -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ - -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi;libunwind' \ + -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \ + -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \ -G "Unix Makefiles" \ ../llvm-project/runtimes/ -make -j cxx cxxabi unwind +make -j cxx cxxabi cd .. From 02c258079e6dafb0e279a4fc75297c37bb778df9 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 12 Mar 2025 16:14:43 +0300 Subject: [PATCH 327/561] CI: only clone/fetch the parts of LLVM monorepo that we need This ends up being *much* faster, noticeably speeding up these jobs. --- .github/libcxx-setup.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/libcxx-setup.sh b/.github/libcxx-setup.sh index 1bd972fbca..d00e495e58 100755 --- a/.github/libcxx-setup.sh +++ b/.github/libcxx-setup.sh @@ -3,7 +3,12 @@ set -e # Checkout LLVM sources -git clone --depth=1 --branch llvmorg-19.1.6 https://github.com/llvm/llvm-project.git llvm-project +git clone --filter=blob:none --depth=1 --branch llvmorg-19.1.6 --no-checkout https://github.com/llvm/llvm-project.git llvm-project +cd llvm-project +git sparse-checkout set --cone +git checkout llvmorg-19.1.6 +git sparse-checkout set cmake llvm/cmake runtimes libcxx libcxxabi +cd .. ## Setup libc++ options if [ -z "$BUILD_32_BITS" ]; then @@ -20,6 +25,9 @@ cmake -DCMAKE_C_COMPILER=${CC} \ -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \ + -DLLVM_INCLUDE_TESTS=OFF \ + -DLIBCXX_INCLUDE_TESTS=OFF \ + -DLIBCXX_INCLUDE_BENCHMARKS=OFF \ -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \ -G "Unix Makefiles" \ ../llvm-project/runtimes/ From 1de7d6aeae3a33f8426be0a7c9f7388a8e7cdf25 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 12 Mar 2025 16:43:42 +0300 Subject: [PATCH 328/561] CI: use Ninja in sanitizer jobs --- .github/libcxx-setup.sh | 6 +++--- .github/workflows/sanitizer.yml | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/libcxx-setup.sh b/.github/libcxx-setup.sh index d00e495e58..8966194d59 100755 --- a/.github/libcxx-setup.sh +++ b/.github/libcxx-setup.sh @@ -17,7 +17,8 @@ fi ## Build and install libc++ (Use unstable ABI for better sanitizer coverage) mkdir llvm-build && cd llvm-build -cmake -DCMAKE_C_COMPILER=${CC} \ +cmake -GNinja \ + -DCMAKE_C_COMPILER=${CC} \ -DCMAKE_CXX_COMPILER=${CXX} \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=/usr \ @@ -29,7 +30,6 @@ cmake -DCMAKE_C_COMPILER=${CC} \ -DLIBCXX_INCLUDE_TESTS=OFF \ -DLIBCXX_INCLUDE_BENCHMARKS=OFF \ -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \ - -G "Unix Makefiles" \ ../llvm-project/runtimes/ -make -j cxx cxxabi +cmake --build . -- cxx cxxabi cd .. diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index dcf373a83e..9eb9947588 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -18,6 +18,11 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: + - name: Installing build dependencies + run: | + sudo apt update + sudo apt install ninja-build + - uses: actions/checkout@v4 - name: configure msan env @@ -75,7 +80,7 @@ jobs: working-directory: ${{ runner.workspace }}/_build run: > VERBOSE=1 - cmake $GITHUB_WORKSPACE + cmake -GNinja $GITHUB_WORKSPACE -DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF -DBENCHMARK_ENABLE_LIBPFM=OFF -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON From dafc6347e2dfbab301a756f9b0fbc19506ef2997 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 12 Mar 2025 16:56:09 +0300 Subject: [PATCH 329/561] CI: switch to ninja on all jobs --- .github/workflows/bazel.yml | 3 +++ .github/workflows/build-and-test-min-cmake.yml | 3 +++ .github/workflows/build-and-test-perfcounters.yml | 3 +++ .github/workflows/build-and-test.yml | 7 +++++++ .github/workflows/clang-format-lint.yml | 3 +++ .github/workflows/clang-tidy-lint.yml | 3 +++ .github/workflows/doxygen.yml | 3 +++ .github/workflows/pre-commit.yml | 3 +++ .github/workflows/sanitizer.yml | 6 +----- .github/workflows/test_bindings.yml | 3 +++ .github/workflows/wheels.yml | 3 +++ 11 files changed, 35 insertions(+), 5 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index ea231a3c4d..d96687797f 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -4,6 +4,9 @@ on: push: {} pull_request: {} +env: + CMAKE_GENERATOR: Ninja + jobs: build_and_test_default: name: bazel.${{ matrix.os }} diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 2509984204..2b56e6a63d 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +env: + CMAKE_GENERATOR: Ninja + jobs: job: name: ${{ matrix.os }}.min-cmake diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 319d42d87e..d12d020e3b 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +env: + CMAKE_GENERATOR: Ninja + jobs: job: # TODO(dominic): Extend this to include compiler and set through env: CC/CXX. diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8394d10129..8f061e14a6 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +env: + CMAKE_GENERATOR: Ninja + jobs: # TODO: add 32-bit builds (g++ and clang++) for ubuntu # (requires g++-multilib and libc6:i386) @@ -23,6 +26,10 @@ jobs: lib: ['shared', 'static'] steps: + - name: Install dependencies (macos) + if: runner.os == 'macOS' + run: brew install ninja + - uses: actions/checkout@v4 - name: build diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index de3e5912f6..3956516752 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -3,6 +3,9 @@ on: push: {} pull_request: {} +env: + CMAKE_GENERATOR: Ninja + jobs: job: name: check-clang-format diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index e38153b823..b3a8964cbd 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -4,6 +4,9 @@ on: push: {} pull_request: {} +env: + CMAKE_GENERATOR: Ninja + jobs: job: name: run-clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 40c1cb4ebc..bcab2c23f3 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +env: + CMAKE_GENERATOR: Ninja + jobs: build-and-deploy: name: Build HTML documentation diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 8b217e981d..d56dde93f9 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +env: + CMAKE_GENERATOR: Ninja + jobs: pre-commit: runs-on: ubuntu-latest diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 9eb9947588..05c265bbba 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -5,6 +5,7 @@ on: pull_request: {} env: + CMAKE_GENERATOR: Ninja UBSAN_OPTIONS: "print_stacktrace=1" jobs: @@ -18,11 +19,6 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - name: Installing build dependencies - run: | - sudo apt update - sudo apt install ninja-build - - uses: actions/checkout@v4 - name: configure msan env diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index b6ac9be8cb..df02c9f136 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +env: + CMAKE_GENERATOR: Ninja + jobs: python_bindings: name: Test GBM Python ${{ matrix.python-version }} bindings on ${{ matrix.os }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 0569dcc90f..d24db9c7cc 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -6,6 +6,9 @@ on: types: - published +env: + CMAKE_GENERATOR: Ninja + jobs: build_sdist: name: Build source distribution From 45ded53f70e129411b1a00de3876b604f049984e Mon Sep 17 00:00:00 2001 From: Richard Cole Date: Wed, 12 Mar 2025 14:40:24 +0000 Subject: [PATCH 330/561] update version of gtest to v1.15.2 (latest) and also the cmake config (#1864) * update version of gtest to v1.15.2 (latest) and also the cmake configuration to avoid deprecation warnings * `cmake/GoogleTest.cmake.in`: do a shallow clone of google test --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> Co-authored-by: Roman Lebedev --- cmake/GoogleTest.cmake.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/GoogleTest.cmake.in b/cmake/GoogleTest.cmake.in index c791446754..6473892489 100644 --- a/cmake/GoogleTest.cmake.in +++ b/cmake/GoogleTest.cmake.in @@ -34,11 +34,12 @@ else() message(SEND_ERROR "Did not find Google Test sources! Either pass correct path in GOOGLETEST_PATH, or enable BENCHMARK_DOWNLOAD_DEPENDENCIES, or disable BENCHMARK_USE_BUNDLED_GTEST, or disable BENCHMARK_ENABLE_GTEST_TESTS / BENCHMARK_ENABLE_TESTING.") return() else() - message(WARNING "Did not find Google Test sources! Fetching from web...") + message(STATUS "Did not find Google Test sources! Fetching from web...") ExternalProject_Add( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG "v1.14.0" + GIT_TAG "v1.15.2" + GIT_SHALLOW "ON" PREFIX "${CMAKE_BINARY_DIR}" STAMP_DIR "${CMAKE_BINARY_DIR}/stamp" DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/download" From 1bc59dce278b9145f18ef88d31d373c4ba939dc4 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 17 Mar 2025 12:18:19 +0300 Subject: [PATCH 331/561] Finish cxx version bump (#1948) * `CMakeLists.txt`: drop hopefully obsolete code * README.md: update * Unbreak `BENCHMARK_HAS_CXX11` macro 835365f99a0b9ec338b6748f5ccb96a3673eeccc stopped defining it, but didn't un-conditionalize the code guarded under it... * Drop `BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK` We no longer support such an old gcc version * `docs/user_guide.md`: proofread * Add a test to ensure that `benchmark.h` remains C++14 header * Revert `[[maybe_unused]]` changes - it requires C++17 * Also support C++11 standard for using the library I don't think we want to support C++03 though, but i suppose C++11 is palatable, at least right now. --- CMakeLists.txt | 12 +--- README.md | 4 +- docs/user_guide.md | 19 +++--- include/benchmark/benchmark.h | 100 +++++++++++++++++++------------- test/BUILD | 16 +++++ test/CMakeLists.txt | 12 ++++ test/basic_test.cc | 3 - test/benchmark_test.cc | 6 -- test/cxx11_test.cc | 12 ++++ test/donotoptimize_test.cc | 2 - test/register_benchmark_test.cc | 7 --- 11 files changed, 113 insertions(+), 80 deletions(-) create mode 100644 test/cxx11_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index fd6906040d..4f67ff5e61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,17 +306,11 @@ if (BENCHMARK_USE_LIBCXX) endif() endif(BENCHMARK_USE_LIBCXX) -set(EXTRA_CXX_FLAGS "") -if (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - # Clang on Windows fails to compile the regex feature check under C++11 - set(EXTRA_CXX_FLAGS "-DCMAKE_CXX_STANDARD=14") -endif() - # C++ feature checks # Determine the correct regular expression engine to use -cxx_feature_check(STD_REGEX ${EXTRA_CXX_FLAGS}) -cxx_feature_check(GNU_POSIX_REGEX ${EXTRA_CXX_FLAGS}) -cxx_feature_check(POSIX_REGEX ${EXTRA_CXX_FLAGS}) +cxx_feature_check(STD_REGEX) +cxx_feature_check(GNU_POSIX_REGEX) +cxx_feature_check(POSIX_REGEX) if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX) message(FATAL_ERROR "Failed to determine the source files for the regular expression backend") endif() diff --git a/README.md b/README.md index b30e57cfd3..4e730256b6 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ IRC channels: ## Requirements -The library can be used with C++03. However, it requires C++14 to build, +The library can be used with C++11. However, it requires C++17 to build, including compiler and standard library support. _See [dependencies.md](docs/dependencies.md) for more details regarding supported @@ -190,7 +190,7 @@ be under the build directory you created. ```bash # Example on linux after running the build steps above. Assumes the # `benchmark` and `build` directories are under the current directory. -$ g++ mybenchmark.cc -std=c++14 -isystem benchmark/include \ +$ g++ mybenchmark.cc -std=c++11 -isystem benchmark/include \ -Lbenchmark/build/src -lbenchmark -lpthread -o mybenchmark ``` diff --git a/docs/user_guide.md b/docs/user_guide.md index 315276277b..b3c1cce8da 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -462,7 +462,7 @@ BENCHMARK(BM_SetInsert)->Apply(CustomArguments); ### Passing Arbitrary Arguments to a Benchmark -In C++11 it is possible to define a benchmark that takes an arbitrary number +It is possible to define a benchmark that takes an arbitrary number of extra arguments. The `BENCHMARK_CAPTURE(func, test_case_name, ...args)` macro creates a benchmark that invokes `func` with the `benchmark::State` as the first argument followed by the specified `args...`. @@ -563,22 +563,19 @@ template void BM_Sequential(benchmark::State& state) { state.SetBytesProcessed( static_cast(state.iterations())*state.range(0)); } -// C++03 -BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); -// C++11 or newer, you can use the BENCHMARK macro with template parameters: +// You can use the BENCHMARK macro with template parameters: BENCHMARK(BM_Sequential>)->Range(1<<0, 1<<10); +// Old, legacy verbose C++03 syntax: +BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); + ``` Three macros are provided for adding benchmark templates. ```c++ -#ifdef BENCHMARK_HAS_CXX11 #define BENCHMARK(func<...>) // Takes any number of parameters. -#else // C++ < C++11 -#define BENCHMARK_TEMPLATE(func, arg1) -#endif #define BENCHMARK_TEMPLATE1(func, arg1) #define BENCHMARK_TEMPLATE2(func, arg1, arg2) ``` @@ -740,12 +737,10 @@ is 1k a 1000 (default, `benchmark::Counter::OneK::kIs1000`), or 1024 state.counters["BytesProcessed"] = Counter(state.range(0), benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::OneK::kIs1024); ``` -When you're compiling in C++11 mode or later you can use `insert()` with -`std::initializer_list`: +You can use `insert()` with `std::initializer_list`: ```c++ - // With C++11, this can be done: state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}}); // ... instead of: state.counters["Foo"] = numFoos; @@ -1249,7 +1244,7 @@ static void BM_test_ranged_fo(benchmark::State & state) { ## A Faster KeepRunning Loop -In C++11 mode, a ranged-based for loop should be used in preference to +A ranged-based for loop should be used in preference to the `KeepRunning` loop for running the benchmarks. For example: ```c++ diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 663953de99..c9a758bc47 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -191,6 +191,14 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete +#ifdef BENCHMARK_HAS_CXX17 +#define BENCHMARK_UNUSED [[maybe_unused]] +#elif defined(__GNUC__) || defined(__clang__) +#define BENCHMARK_UNUSED __attribute__((unused)) +#else +#define BENCHMARK_UNUSED +#endif + // Used to annotate functions, methods and classes so they // are not optimized by the compiler. Useful for tests // where you expect loops to stay in place churning cycles @@ -303,6 +311,18 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #endif // _MSC_VER_ namespace benchmark { + +namespace internal { +#if (__cplusplus < 201402L || (defined(_MSC_VER) && _MSVC_LANG < 201402L)) +template +std::unique_ptr make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} +#else +using ::std::make_unique; +#endif +} // namespace internal + class BenchmarkReporter; class State; @@ -472,7 +492,7 @@ BENCHMARK_EXPORT Benchmark* RegisterBenchmarkInternal( // Ensure that the standard streams are properly initialized in every TU. BENCHMARK_EXPORT int InitializeStreams(); -[[maybe_unused]] static int stream_init_anchor = InitializeStreams(); +BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); } // namespace internal @@ -1026,7 +1046,7 @@ inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n, } struct State::StateIterator { - struct [[maybe_unused]] Value {}; + struct BENCHMARK_UNUSED Value {}; typedef std::forward_iterator_tag iterator_category; typedef Value value_type; typedef Value reference; @@ -1371,7 +1391,7 @@ class LambdaBenchmark : public Benchmark { inline internal::Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn) { return internal::RegisterBenchmarkInternal( - std::make_unique(name, fn)); + benchmark::internal::make_unique(name, fn)); } template @@ -1379,19 +1399,16 @@ internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { using BenchType = internal::LambdaBenchmark::type>; return internal::RegisterBenchmarkInternal( - std::make_unique(name, std::forward(fn))); + benchmark::internal::make_unique(name, + std::forward(fn))); } -#if (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) template internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn, Args&&... args) { return benchmark::RegisterBenchmark( name, [=](benchmark::State& st) { fn(st, args...); }); } -#else -#define BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK -#endif // The base class for all fixture tests. class Fixture : public internal::Benchmark { @@ -1442,13 +1459,14 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_PRIVATE_DECLARE(n) \ /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ static ::benchmark::internal::Benchmark const* const BENCHMARK_PRIVATE_NAME( \ - n) [[maybe_unused]] + n) BENCHMARK_UNUSED #define BENCHMARK(...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - std::make_unique<::benchmark::internal::FunctionBenchmark>( \ - #__VA_ARGS__, __VA_ARGS__))) + benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>(#__VA_ARGS__, \ + __VA_ARGS__))) // Old-style macros #define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) @@ -1469,11 +1487,12 @@ class Fixture : public internal::Benchmark { //} // /* Registers a benchmark named "BM_takes_args/int_string_test` */ // BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); -#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ - BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - std::make_unique<::benchmark::internal::FunctionBenchmark>( \ - #func "/" #test_case_name, \ +#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #func "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) // This will register a benchmark for a templatized function. For example: @@ -1484,22 +1503,24 @@ class Fixture : public internal::Benchmark { // BENCHMARK_TEMPLATE(BM_Foo, 1); // // will register BM_Foo<1> as a benchmark. -#define BENCHMARK_TEMPLATE1(n, a) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - std::make_unique<::benchmark::internal::FunctionBenchmark>( \ - #n "<" #a ">", n))) - -#define BENCHMARK_TEMPLATE2(n, a, b) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - std::make_unique<::benchmark::internal::FunctionBenchmark>( \ - #n "<" #a "," #b ">", n))) - -#define BENCHMARK_TEMPLATE(n, ...) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - std::make_unique<::benchmark::internal::FunctionBenchmark>( \ +#define BENCHMARK_TEMPLATE1(n, a) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>(#n "<" #a ">", n))) + +#define BENCHMARK_TEMPLATE2(n, a, b) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>(#n "<" #a "," #b ">", \ + n))) + +#define BENCHMARK_TEMPLATE(n, ...) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) // This will register a benchmark for a templatized function, @@ -1517,12 +1538,13 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_TEMPLATE1_CAPTURE(func, a, test_case_name, ...) \ BENCHMARK_CAPTURE(func, test_case_name, __VA_ARGS__) -#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ - BENCHMARK_PRIVATE_DECLARE(func) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - std::make_unique<::benchmark::internal::FunctionBenchmark>( \ - #func "<" #a "," #b ">" \ - "/" #test_case_name, \ +#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(func) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #func "<" #a "," #b ">" \ + "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) #define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ @@ -1591,7 +1613,7 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ BENCHMARK_PRIVATE_DECLARE(TestName) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - std::make_unique())) + benchmark::internal::make_unique())) // This macro will define and register a benchmark within a fixture class. #define BENCHMARK_F(BaseClass, Method) \ diff --git a/test/BUILD b/test/BUILD index e3558a94d6..9a26970672 100644 --- a/test/BUILD +++ b/test/BUILD @@ -102,11 +102,27 @@ cc_library( ["*_test.cc"], exclude = [ "*_assembly_test.cc", + "cxx11_test.cc", "link_main_test.cc", ], ) ] +cc_test( + name = "cxx11_test", + size = "small", + srcs = ["cxx11_test.cc"], + copts = TEST_COPTS + ["-std=c++11"], + target_compatible_with = select({ + "//:windows": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + deps = [ + ":output_test_helper", + "//:benchmark_main", + ], +) + cc_test( name = "link_main_test", size = "small", diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a7e7122dd2..df575d9be1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -73,6 +73,18 @@ macro(benchmark_add_test) endmacro(benchmark_add_test) # Demonstration executable + +compile_benchmark_test_with_main(cxx11_test) +if(DEFINED MSVC) + # MSVC does not really support C++11. + set_property(TARGET cxx11_test PROPERTY CXX_STANDARD 14) +else() + set_property(TARGET cxx11_test PROPERTY CXX_STANDARD 11) +endif() +set_property(TARGET cxx11_test PROPERTY CXX_STANDARD_REQUIRED ON) +set_property(TARGET cxx11_test PROPERTY CXX_EXTENSIONS OFF) +benchmark_add_test(NAME cxx11_test COMMAND cxx11_test --benchmark_min_time=0.01s) + compile_benchmark_test(benchmark_test) benchmark_add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01s) diff --git a/test/basic_test.cc b/test/basic_test.cc index c3ac4946d8..b51494bdc4 100644 --- a/test/basic_test.cc +++ b/test/basic_test.cc @@ -143,7 +143,6 @@ void BM_RangedFor(benchmark::State& state) { } BENCHMARK(BM_RangedFor); -#ifdef BENCHMARK_HAS_CXX11 template void BM_OneTemplateFunc(benchmark::State& state) { auto arg = state.range(0); @@ -168,8 +167,6 @@ void BM_TwoTemplateFunc(benchmark::State& state) { BENCHMARK(BM_TwoTemplateFunc)->Arg(1); BENCHMARK(BM_TwoTemplateFunc)->Arg(1); -#endif // BENCHMARK_HAS_CXX11 - // Ensure that StateIterator provides all the necessary typedefs required to // instantiate std::iterator_traits. static_assert( diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index e00f153527..141f286fea 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -131,9 +131,7 @@ BENCHMARK_TEMPLATE2(BM_Sequential, std::vector, int) ->Range(1 << 0, 1 << 10); BENCHMARK_TEMPLATE(BM_Sequential, std::list)->Range(1 << 0, 1 << 10); // Test the variadic version of BENCHMARK_TEMPLATE in C++11 and beyond. -#ifdef BENCHMARK_HAS_CXX11 BENCHMARK_TEMPLATE(BM_Sequential, std::vector, int)->Arg(512); -#endif static void BM_StringCompare(benchmark::State& state) { size_t len = static_cast(state.range(0)); @@ -225,8 +223,6 @@ static void BM_ManualTiming(benchmark::State& state) { BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseRealTime(); BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseManualTime(); -#ifdef BENCHMARK_HAS_CXX11 - template void BM_with_args(benchmark::State& state, Args&&...) { for (auto _ : state) { @@ -267,8 +263,6 @@ void BM_template1_capture(benchmark::State& state, ExtraArgs&&... extra_args) { BENCHMARK_TEMPLATE1_CAPTURE(BM_template1_capture, void, foo, 24UL); BENCHMARK_CAPTURE(BM_template1_capture, foo, 24UL); -#endif // BENCHMARK_HAS_CXX11 - static void BM_DenseThreadRanges(benchmark::State& st) { switch (st.range(0)) { case 1: diff --git a/test/cxx11_test.cc b/test/cxx11_test.cc new file mode 100644 index 0000000000..db1a993343 --- /dev/null +++ b/test/cxx11_test.cc @@ -0,0 +1,12 @@ +#include "benchmark/benchmark.h" + +#if defined(_MSC_VER) +#if _MSVC_LANG != 201402L +// MSVC, even in C++11 mode, dooes not claim to be in C++11 mode. +#error "Trying to compile C++11 test with wrong C++ standard" +#endif // _MSVC_LANG +#else // Non-MSVC +#if __cplusplus != 201103L +#error "Trying to compile C++11 test with wrong C++ standard" +#endif // Non-MSVC +#endif diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc index 75db934b97..5c9a4583de 100644 --- a/test/donotoptimize_test.cc +++ b/test/donotoptimize_test.cc @@ -62,8 +62,6 @@ int main(int /*unused*/, char* /*unused*/[]) { BitRef lval = BitRef::Make(); benchmark::DoNotOptimize(lval); -#ifdef BENCHMARK_HAS_CXX11 // Check that accept rvalue. benchmark::DoNotOptimize(BitRef::Make()); -#endif } diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index e443ab723f..1a188142de 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -77,7 +77,6 @@ ADD_CASES({"BM_function"}, {"BM_function_manual_registration"}); // Note: GCC <= 4.8 do not support this form of RegisterBenchmark because they // reject the variadic pack expansion of lambda captures. //----------------------------------------------------------------------------// -#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK void BM_extra_args(benchmark::State& st, const char* label) { for (auto _ : st) { @@ -95,8 +94,6 @@ int RegisterFromFunction() { const int dummy2 = RegisterFromFunction(); ADD_CASES({"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}); -#endif // BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK - //----------------------------------------------------------------------------// // Test RegisterBenchmark with DISABLED_ benchmark //----------------------------------------------------------------------------// @@ -121,14 +118,11 @@ struct CustomFixture { }; void TestRegistrationAtRuntime() { -#ifdef BENCHMARK_HAS_CXX11 { CustomFixture fx; benchmark::RegisterBenchmark("custom_fixture", fx); AddCases({std::string("custom_fixture")}); } -#endif -#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK { const char* x = "42"; auto capturing_lam = [=](benchmark::State& st) { @@ -139,7 +133,6 @@ void TestRegistrationAtRuntime() { benchmark::RegisterBenchmark("lambda_benchmark", capturing_lam); AddCases({{"lambda_benchmark", x}}); } -#endif } // Test that all benchmarks, registered at either during static init or runtime, From afa23b7699c17f1e26c88cbf95257b20d78d6247 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 25 Mar 2025 09:17:34 +0000 Subject: [PATCH 332/561] bump version to 1.9.2 in readiness for release. #1957 --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f67ff5e61..fcbba0d03c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.13...3.22) -project (benchmark VERSION 1.9.1 LANGUAGES CXX) +project (benchmark VERSION 1.9.2 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index d346b72074..66c990663a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.9.1", + version = "1.9.2", ) bazel_dep(name = "bazel_skylib", version = "1.7.1") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 3685928f21..e6665135eb 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -50,7 +50,7 @@ def my_benchmark(state): oNSquared as oNSquared, ) -__version__ = "1.9.1" +__version__ = "1.9.2" class __OptionMaker: From cb4239f398b6d833476e4320b5aaecedbd7512eb Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 27 Mar 2025 05:22:25 +0000 Subject: [PATCH 333/561] Use the top-level ::benchmark namespace to resolve `make_unique` (#1960) Fixes #1959 --- include/benchmark/benchmark.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index c9a758bc47..624ab29c6e 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1391,7 +1391,8 @@ class LambdaBenchmark : public Benchmark { inline internal::Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn) { return internal::RegisterBenchmarkInternal( - benchmark::internal::make_unique(name, fn)); + ::benchmark::internal::make_unique(name, + fn)); } template @@ -1399,8 +1400,8 @@ internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { using BenchType = internal::LambdaBenchmark::type>; return internal::RegisterBenchmarkInternal( - benchmark::internal::make_unique(name, - std::forward(fn))); + ::benchmark::internal::make_unique(name, + std::forward(fn))); } template @@ -1464,7 +1465,7 @@ class Fixture : public internal::Benchmark { #define BENCHMARK(...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - benchmark::internal::make_unique< \ + ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>(#__VA_ARGS__, \ __VA_ARGS__))) @@ -1490,7 +1491,7 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_CAPTURE(func, test_case_name, ...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - benchmark::internal::make_unique< \ + ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>( \ #func "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) @@ -1506,20 +1507,20 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_TEMPLATE1(n, a) \ BENCHMARK_PRIVATE_DECLARE(n) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - benchmark::internal::make_unique< \ + ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>(#n "<" #a ">", n))) #define BENCHMARK_TEMPLATE2(n, a, b) \ BENCHMARK_PRIVATE_DECLARE(n) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - benchmark::internal::make_unique< \ + ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>(#n "<" #a "," #b ">", \ n))) #define BENCHMARK_TEMPLATE(n, ...) \ BENCHMARK_PRIVATE_DECLARE(n) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - benchmark::internal::make_unique< \ + ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>( \ #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) @@ -1541,7 +1542,7 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ BENCHMARK_PRIVATE_DECLARE(func) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - benchmark::internal::make_unique< \ + ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>( \ #func "<" #a "," #b ">" \ "/" #test_case_name, \ @@ -1613,7 +1614,7 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ BENCHMARK_PRIVATE_DECLARE(TestName) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ - benchmark::internal::make_unique())) + ::benchmark::internal::make_unique())) // This macro will define and register a benchmark within a fixture class. #define BENCHMARK_F(BaseClass, Method) \ From 2918a094b0068f28e4a6723406252855d57527b3 Mon Sep 17 00:00:00 2001 From: krzikalla <5096821+krzikalla@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:10:05 +0100 Subject: [PATCH 334/561] Refactor threading run (#1961) * ThreadManager::WaitForAllThreads removed * WaitForAllThreads was only called either in single threaded environments or just before all threads are joined anyway. As this doesn't add a useful synchronization point, it's removed. * Formatting issue * Thread Sanitizer satisfied * More formatting issues --- src/benchmark_runner.cc | 3 --- src/thread_manager.h | 24 +++--------------------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index b062c7cead..55ad69ce08 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -302,7 +302,6 @@ BenchmarkRunner::IterationResults BenchmarkRunner::DoNIterations() { /*profiler_manager=*/nullptr); // The main thread has finished. Now let's wait for the other threads. - manager->WaitForAllThreads(); for (std::thread& thread : pool) { thread.join(); } @@ -434,7 +433,6 @@ MemoryManager::Result BenchmarkRunner::RunMemoryManager( RunInThread(&b, memory_iterations, 0, manager.get(), perf_counters_measurement_ptr, /*profiler_manager=*/nullptr); - manager->WaitForAllThreads(); manager.reset(); b.Teardown(); MemoryManager::Result memory_result; @@ -450,7 +448,6 @@ void BenchmarkRunner::RunProfilerManager(IterationCount profile_iterations) { RunInThread(&b, profile_iterations, 0, manager.get(), /*perf_counters_measurement_ptr=*/nullptr, /*profiler_manager=*/profiler_manager); - manager->WaitForAllThreads(); manager.reset(); b.Teardown(); } diff --git a/src/thread_manager.h b/src/thread_manager.h index 819b3c44db..a0ac37a8b2 100644 --- a/src/thread_manager.h +++ b/src/thread_manager.h @@ -11,30 +11,15 @@ namespace internal { class ThreadManager { public: - explicit ThreadManager(int num_threads) - : alive_threads_(num_threads), start_stop_barrier_(num_threads) {} + explicit ThreadManager(int num_threads) : start_stop_barrier_(num_threads) {} Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) { return benchmark_mutex_; } - bool StartStopBarrier() EXCLUDES(end_cond_mutex_) { - return start_stop_barrier_.wait(); - } - - void NotifyThreadComplete() EXCLUDES(end_cond_mutex_) { - start_stop_barrier_.removeThread(); - if (--alive_threads_ == 0) { - MutexLock lock(end_cond_mutex_); - end_condition_.notify_all(); - } - } + bool StartStopBarrier() { return start_stop_barrier_.wait(); } - void WaitForAllThreads() EXCLUDES(end_cond_mutex_) { - MutexLock lock(end_cond_mutex_); - end_condition_.wait(lock.native_handle(), - [this]() { return alive_threads_ == 0; }); - } + void NotifyThreadComplete() { start_stop_barrier_.removeThread(); } struct Result { IterationCount iterations = 0; @@ -51,10 +36,7 @@ class ThreadManager { private: mutable Mutex benchmark_mutex_; - std::atomic alive_threads_; Barrier start_stop_barrier_; - Mutex end_cond_mutex_; - Condition end_condition_; }; } // namespace internal From 0da57b85cf23e48d0e515f58c65a25425dbde012 Mon Sep 17 00:00:00 2001 From: krzikalla <5096821+krzikalla@users.noreply.github.com> Date: Sat, 29 Mar 2025 08:49:25 +0100 Subject: [PATCH 335/561] Threading api refactor (#1955) Refactor the multi-threading api to support using custom user-provided thread factory instead of always spawning POSIX Threads. --- docs/user_guide.md | 40 ++++++++ include/benchmark/benchmark.h | 15 +++ src/benchmark_api_internal.h | 3 + src/benchmark_register.cc | 5 + src/benchmark_runner.cc | 56 +++++++---- src/benchmark_runner.h | 3 +- test/CMakeLists.txt | 3 + test/manual_threading_test.cc | 174 ++++++++++++++++++++++++++++++++++ 8 files changed, 281 insertions(+), 18 deletions(-) create mode 100644 test/manual_threading_test.cc diff --git a/docs/user_guide.md b/docs/user_guide.md index b3c1cce8da..0bcfe15229 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -863,6 +863,46 @@ BENCHMARK(BM_test)->Range(8, 8<<10)->UseRealTime(); Without `UseRealTime`, CPU time is used by default. +### Manual Multithreaded Benchmarks + +Google/benchmark uses `std::thread` as multithreading environment per default. +If you want to use another multithreading environment (e.g. OpenMP), you can provide +a factory function to your benchmark using the `ThreadRunner` function. +The factory function takes the number of threads as argument and creates a custom class +derived from `benchmark::ThreadRunnerBase`. +This custom class must override the function +`void RunThreads(const std::function& fn)`. +`RunThreads` is called by the main thread and spawns the requested number of threads. +Each spawned thread must call `fn(thread_index)`, where `thread_index` is its own +thread index. Before `RunThreads` returns, all spawned threads must be joined. +```c++ +class OpenMPThreadRunner : public benchmark::ThreadRunnerBase +{ + OpenMPThreadRunner(int num_threads) + : num_threads_(num_threads) + {} + + void RunThreads(const std::function& fn) final + { +#pragma omp parallel num_threads(num_threads_) + fn(omp_get_thread_num()); + } + +private: + int num_threads_; +}; + +BENCHMARK(BM_MultiThreaded) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(1)->Threads(2)->Threads(4); +``` +The above example creates a parallel OpenMP region before it enters `BM_MultiThreaded`. +The actual benchmark code can remain the same and is therefore not tied to a specific +thread runner. The measurement does not include the time for creating and joining the +threads. + ## CPU Timers diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 624ab29c6e..5e40975893 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1093,8 +1093,18 @@ inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { return StateIterator(); } +// Base class for user-defined multi-threading +struct ThreadRunnerBase { + virtual ~ThreadRunnerBase() {} + virtual void RunThreads(const std::function& fn) = 0; +}; + namespace internal { +// Define alias of ThreadRunner factory function type +using threadrunner_factory = + std::function(int)>; + typedef void(Function)(State&); // ------------------------------------------------------ @@ -1299,6 +1309,9 @@ class BENCHMARK_EXPORT Benchmark { // Equivalent to ThreadRange(NumCPUs(), NumCPUs()) Benchmark* ThreadPerCpu(); + // Sets a user-defined threadrunner (see ThreadRunnerBase) + Benchmark* ThreadRunner(threadrunner_factory&& factory); + virtual void Run(State& state) = 0; TimeUnit GetTimeUnit() const; @@ -1340,6 +1353,8 @@ class BENCHMARK_EXPORT Benchmark { callback_function setup_; callback_function teardown_; + threadrunner_factory threadrunner_; + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(Benchmark); }; diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h index 82ab71f4bc..efa0602173 100644 --- a/src/benchmark_api_internal.h +++ b/src/benchmark_api_internal.h @@ -41,6 +41,9 @@ class BenchmarkInstance { int threads() const { return threads_; } void Setup() const; void Teardown() const; + const auto& GetUserThreadRunnerFactory() const { + return benchmark_.threadrunner_; + } State Run(IterationCount iters, int thread_id, internal::ThreadTimer* timer, internal::ThreadManager* manager, diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 8b94540468..d8cefe480c 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -484,6 +484,11 @@ Benchmark* Benchmark::ThreadPerCpu() { return this; } +Benchmark* Benchmark::ThreadRunner(threadrunner_factory&& factory) { + threadrunner_ = std::move(factory); + return this; +} + void Benchmark::SetName(const std::string& name) { name_ = name; } const char* Benchmark::GetName() const { return name_.c_str(); } diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 55ad69ce08..427bd857f7 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -182,6 +183,38 @@ IterationCount ComputeIters(const benchmark::internal::BenchmarkInstance& b, return iters_or_time.iters; } +class ThreadRunnerDefault : public ThreadRunnerBase { + public: + explicit ThreadRunnerDefault(int num_threads) + : pool(static_cast(num_threads - 1)) {} + + void RunThreads(const std::function& fn) final { + // Run all but one thread in separate threads + for (std::size_t ti = 0; ti < pool.size(); ++ti) { + pool[ti] = std::thread(fn, static_cast(ti + 1)); + } + // And run one thread here directly. + // (If we were asked to run just one thread, we don't create new threads.) + // Yes, we need to do this here *after* we start the separate threads. + fn(0); + + // The main thread has finished. Now let's wait for the other threads. + for (std::thread& thread : pool) { + thread.join(); + } + } + + private: + std::vector pool; +}; + +std::unique_ptr GetThreadRunner( + const threadrunner_factory& userThreadRunnerFactory, int num_threads) { + return userThreadRunnerFactory + ? userThreadRunnerFactory(num_threads) + : std::make_unique(num_threads); +} + } // end namespace BenchTimeType ParseBenchMinTime(const std::string& value) { @@ -258,7 +291,8 @@ BenchmarkRunner::BenchmarkRunner( has_explicit_iteration_count(b.iterations() != 0 || parsed_benchtime_flag.tag == BenchTimeType::ITERS), - pool(static_cast(b.threads() - 1)), + thread_runner( + GetThreadRunner(b.GetUserThreadRunnerFactory(), b.threads())), iters(FLAGS_benchmark_dry_run ? 1 : (has_explicit_iteration_count @@ -289,22 +323,10 @@ BenchmarkRunner::IterationResults BenchmarkRunner::DoNIterations() { std::unique_ptr manager; manager.reset(new internal::ThreadManager(b.threads())); - // Run all but one thread in separate threads - for (std::size_t ti = 0; ti < pool.size(); ++ti) { - pool[ti] = std::thread(&RunInThread, &b, iters, static_cast(ti + 1), - manager.get(), perf_counters_measurement_ptr, - /*profiler_manager=*/nullptr); - } - // And run one thread here directly. - // (If we were asked to run just one thread, we don't create new threads.) - // Yes, we need to do this here *after* we start the separate threads. - RunInThread(&b, iters, 0, manager.get(), perf_counters_measurement_ptr, - /*profiler_manager=*/nullptr); - - // The main thread has finished. Now let's wait for the other threads. - for (std::thread& thread : pool) { - thread.join(); - } + thread_runner->RunThreads([&](int thread_idx) { + RunInThread(&b, iters, thread_idx, manager.get(), + perf_counters_measurement_ptr, /*profiler_manager=*/nullptr); + }); IterationResults i; // Acquire the measurements/counters from the manager, UNDER THE LOCK! diff --git a/src/benchmark_runner.h b/src/benchmark_runner.h index bc76c81e48..9a2231a2a4 100644 --- a/src/benchmark_runner.h +++ b/src/benchmark_runner.h @@ -15,6 +15,7 @@ #ifndef BENCHMARK_RUNNER_H_ #define BENCHMARK_RUNNER_H_ +#include #include #include @@ -89,7 +90,7 @@ class BenchmarkRunner { int num_repetitions_done = 0; - std::vector pool; + std::unique_ptr thread_runner; IterationCount iters; // preserved between repetitions! // So only the first repetition has to find/calculate it, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index df575d9be1..bde248f0c1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -189,6 +189,9 @@ benchmark_add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmar compile_output_test(internal_threading_test) benchmark_add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01s) +compile_output_test(manual_threading_test) +benchmark_add_test(NAME manual_threading_test COMMAND manual_threading_test --benchmark_min_time=0.01s) + compile_output_test(report_aggregates_only_test) benchmark_add_test(NAME report_aggregates_only_test COMMAND report_aggregates_only_test --benchmark_min_time=0.01s) diff --git a/test/manual_threading_test.cc b/test/manual_threading_test.cc new file mode 100644 index 0000000000..e85d495620 --- /dev/null +++ b/test/manual_threading_test.cc @@ -0,0 +1,174 @@ + +#include +#undef NDEBUG + +#include +#include + +#include "../src/timers.h" +#include "benchmark/benchmark.h" + +namespace { + +const std::chrono::duration time_frame(50); +const double time_frame_in_sec( + std::chrono::duration_cast>>( + time_frame) + .count()); + +void MyBusySpinwait() { + const auto start = benchmark::ChronoClockNow(); + + while (true) { + const auto now = benchmark::ChronoClockNow(); + const auto elapsed = now - start; + + if (std::chrono::duration(elapsed) >= + time_frame) { + return; + } + } +} + +int numRunThreadsCalled_ = 0; + +class ManualThreadRunner : public benchmark::ThreadRunnerBase { + public: + explicit ManualThreadRunner(int num_threads) + : pool(static_cast(num_threads - 1)) {} + + void RunThreads(const std::function& fn) final { + for (std::size_t ti = 0; ti < pool.size(); ++ti) { + pool[ti] = std::thread(fn, static_cast(ti + 1)); + } + + fn(0); + + for (std::thread& thread : pool) { + thread.join(); + } + + ++numRunThreadsCalled_; + } + + private: + std::vector pool; +}; + +// ========================================================================= // +// --------------------------- TEST CASES BEGIN ---------------------------- // +// ========================================================================= // + +// ========================================================================= // +// BM_ManualThreading +// Creation of threads is done before the start of the measurement, +// joining after the finish of the measurement. +void BM_ManualThreading(benchmark::State& state) { + for (auto _ : state) { + MyBusySpinwait(); + state.SetIterationTime(time_frame_in_sec); + } + state.counters["invtime"] = + benchmark::Counter{1, benchmark::Counter::kIsRate}; +} + +} // end namespace + +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(1); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(1) + ->UseRealTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(1) + ->UseManualTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(1) + ->MeasureProcessCPUTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(2); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(2) + ->UseRealTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(2) + ->UseManualTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(2) + ->MeasureProcessCPUTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_ManualThreading) + ->Iterations(1) + ->ThreadRunner([](int num_threads) { + return std::make_unique(num_threads); + }) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +// ========================================================================= // +// ---------------------------- TEST CASES END ----------------------------- // +// ========================================================================= // + +int main(int argc, char* argv[]) { + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + assert(numRunThreadsCalled_ > 0); +} From f828d71c59fd331e56c2a8b57332ab93bc0dea93 Mon Sep 17 00:00:00 2001 From: krzikalla <5096821+krzikalla@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:25:46 +0200 Subject: [PATCH 336/561] Method templates for Fixtures introduced (#1967) --- docs/user_guide.md | 48 +++++++++++++++++++++++++++ include/benchmark/benchmark.h | 30 +++++++++++++++++ test/CMakeLists.txt | 3 ++ test/templated_fixture_method_test.cc | 26 +++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 test/templated_fixture_method_test.cc diff --git a/docs/user_guide.md b/docs/user_guide.md index 0bcfe15229..5fc0db9bcb 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -677,6 +677,54 @@ BENCHMARK_REGISTER_F(MyFixture, DoubleTest)->Threads(2); // `DoubleTest` is now registered. ``` +If you want to use a method template for your fixtures, +which you instantiate afterward, use the following macros: + +* `BENCHMARK_TEMPLATE_METHOD_F(ClassName, Method)` +* `BENCHMARK_TEMPLATE_INSTANTIATE_F(ClassName, Method, ...)` + +With these macros you can define one method for several instantiations. +Example (using `MyFixture` from above): + +```c++ +// Defines `Test` using the class template `MyFixture`. +BENCHMARK_TEMPLATE_METHOD_F(MyFixture, Test)(benchmark::State& st) { + for (auto _ : st) { + ... + } +} + +// Instantiates and registers the benchmark `MyFixture::Test`. +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Test, int)->Threads(2); +// Instantiates and registers the benchmark `MyFixture::Test`. +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Test, double)->Threads(4); +``` + +Inside the method definition of `BENCHMARK_TEMPLATE_METHOD_F` the type `Base` refers +to the type of the instantiated fixture. +Accesses to members of the fixture must be prefixed by `this->`. + +`BENCHMARK_TEMPLATE_METHOD_F`and `BENCHMARK_TEMPLATE_INSTANTIATE_F` can only be used, +if the fixture does not use non-type template parameters. +If you want to pass values as template parameters, use e.g. `std::integral_constant`. +For example: + +```c++ +template +class SizedFixture : public benchmark::Fixture { + static constexpr Size = Sz::value; + int myValue; +}; + +BENCHMARK_TEMPLATE_METHOD_F(SizedFixture, Test)(benchmark::State& st) { + for (auto _ : st) { + this->myValue = Base::Size; + } +} + +BENCHMARK_TEMPLATE_INSTANTIATE_F(SizedFixture, Test, std::integral_constant<5>)->Threads(2); +``` + ## Custom Counters diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 5e40975893..c4b5d89570 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1631,6 +1631,36 @@ class Fixture : public internal::Benchmark { (::benchmark::internal::RegisterBenchmarkInternal( \ ::benchmark::internal::make_unique())) +#define BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ + BaseClass##_##Method##_BenchmarkTemplate + +#define BENCHMARK_TEMPLATE_METHOD_F(BaseClass, Method) \ + template \ + class BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ + : public BaseClass { \ + protected: \ + using Base = BaseClass; \ + void BenchmarkCase(::benchmark::State&) override; \ + }; \ + template \ + void BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ + BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F(BaseClass, Method, \ + UniqueName, ...) \ + class UniqueName : public BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ + BaseClass, Method)<__VA_ARGS__> { \ + public: \ + UniqueName() { this->SetName(#BaseClass "<" #__VA_ARGS__ ">/" #Method); } \ + }; \ + BENCHMARK_PRIVATE_DECLARE(BaseClass##_##Method##_Benchmark) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique())) + +#define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \ + BaseClass, Method, BENCHMARK_PRIVATE_NAME(tf), __VA_ARGS__) + // This macro will define and register a benchmark within a fixture class. #define BENCHMARK_F(BaseClass, Method) \ BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bde248f0c1..b7a6ac4899 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -180,6 +180,9 @@ benchmark_add_test(NAME reporter_output_test COMMAND reporter_output_test --benc compile_output_test(templated_fixture_test) benchmark_add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01s) +compile_output_test(templated_fixture_method_test) +benchmark_add_test(NAME templated_fixture_method_test COMMAND templated_fixture_method_test --benchmark_min_time=0.01s) + compile_output_test(user_counters_test) benchmark_add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s) diff --git a/test/templated_fixture_method_test.cc b/test/templated_fixture_method_test.cc new file mode 100644 index 0000000000..06fc7d83e7 --- /dev/null +++ b/test/templated_fixture_method_test.cc @@ -0,0 +1,26 @@ + +#include +#include + +#include "benchmark/benchmark.h" + +template +class MyFixture : public ::benchmark::Fixture { + public: + MyFixture() : data(0) {} + + T data; + + using type = T; +}; + +BENCHMARK_TEMPLATE_METHOD_F(MyFixture, Foo)(benchmark::State& st) { + for (auto _ : st) { + this->data += typename Base::type(1); + } +} + +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Foo, int); +BENCHMARK_TEMPLATE_INSTANTIATE_F(MyFixture, Foo, double); + +BENCHMARK_MAIN(); From ff52b227dbf0e2981f0940d94b9c47860e98c490 Mon Sep 17 00:00:00 2001 From: krzikalla <5096821+krzikalla@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:02:03 +0200 Subject: [PATCH 337/561] Fixed private macro name issue (#1968) --- docs/user_guide.md | 2 +- include/benchmark/benchmark.h | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 5fc0db9bcb..3b8f9d54c1 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -712,7 +712,7 @@ For example: ```c++ template class SizedFixture : public benchmark::Fixture { - static constexpr Size = Sz::value; + static constexpr auto Size = Sz::value; int myValue; }; diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index c4b5d89570..188377ac48 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1657,9 +1657,10 @@ class Fixture : public internal::Benchmark { (::benchmark::internal::RegisterBenchmarkInternal( \ ::benchmark::internal::make_unique())) -#define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \ - BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \ - BaseClass, Method, BENCHMARK_PRIVATE_NAME(tf), __VA_ARGS__) +#define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \ + BaseClass, Method, BENCHMARK_PRIVATE_NAME(BaseClass##Method), \ + __VA_ARGS__) // This macro will define and register a benchmark within a fixture class. #define BENCHMARK_F(BaseClass, Method) \ From 48f5cc21bac647a8a64e9787cb84f349e334b7ac Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 16 Apr 2025 03:29:10 -0700 Subject: [PATCH 338/561] Deprecate ubuntu-20.04 images in actions (#1971) https://github.com/actions/runner-images/issues/11101 --- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index d12d020e3b..ad92602d82 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-20.04] + os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8f061e14a6..858ea8cce2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-20.04, ubuntu-22.04-arm, macos-latest] + os: [ubuntu-24.04, ubuntu-22.04, ubuntu-24.04-arm, macos-latest] build_type: ['Release', 'Debug'] compiler: ['g++', 'clang++'] lib: ['shared', 'static'] From c19058b4e5ebab2f3cfe79c5267c28e1654e6c6a Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 22 Apr 2025 16:56:31 +0200 Subject: [PATCH 339/561] deps: Update nanobind_bazel to v2.7.0 (#1970) Builds bindings with nanobind v2.7.0, which contains a few bug fixes and improvements. --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 66c990663a..37d9c40078 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -38,4 +38,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "2.5.0", dev_dependency = True) +bazel_dep(name = "nanobind_bazel", version = "2.7.0", dev_dependency = True) From 0e08459200b79c9e91dda70e1eebd7a5dcace763 Mon Sep 17 00:00:00 2001 From: mark-horvath-arm <57909897+mark-horvath-arm@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:17:11 +0200 Subject: [PATCH 340/561] Fix error handling of getloadavg (#1974) getloadavg returns with -1 if cannot obtain load average, but the current source casts the return value to size_t right away. The cast result for such a case is probably maximum unsigned long int, so the resizing of the res vector is certainly going to fail. This change keeps the original return type of getloadavg and casts it just before the resizing of the res vector. --- src/sysinfo.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index c938b360f8..bf2fee85fc 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -850,11 +850,11 @@ std::vector GetLoadAvg() { !(defined(__ANDROID__) && __ANDROID_API__ < 29) static constexpr int kMaxSamples = 3; std::vector res(kMaxSamples, 0.0); - const size_t nelem = static_cast(getloadavg(res.data(), kMaxSamples)); + const auto nelem = getloadavg(res.data(), kMaxSamples); if (nelem < 1) { res.clear(); } else { - res.resize(nelem); + res.resize(static_cast(nelem)); } return res; #else From b616354a7649a08c8fc30c331934601f3907b4e5 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 1 May 2025 15:46:23 +0300 Subject: [PATCH 341/561] Improve user UX on empty benchmarks (#1976) Fixes https://github.com/google/benchmark/issues/1962 --- src/benchmark_runner.cc | 7 +++++-- test/skip_with_error_test.cc | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 427bd857f7..1f5bb6b79f 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -142,8 +142,11 @@ void RunInThread(const BenchmarkInstance* b, IterationCount iters, State st = b->Run(iters, thread_id, &timer, manager, perf_counters_measurement, profiler_manager_); - BM_CHECK(st.skipped() || st.iterations() >= st.max_iterations) - << "Benchmark returned before State::KeepRunning() returned false!"; + if (!(st.skipped() || st.iterations() >= st.max_iterations)) { + st.SkipWithError( + "The benchmark didn't run, nor was it explicitly skipped. Please call " + "'SkipWithXXX` in your benchmark as appropriate."); + } { MutexLock l(manager->GetBenchmarkMutex()); internal::ThreadManager::Result& results = manager->results; diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 769b09db5f..1056f86191 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -200,3 +200,12 @@ int main(int argc, char* argv[]) { return 0; } + +void BM_malformed(benchmark::State&) { + // NOTE: empty body wanted. No thing else. +} +BENCHMARK(BM_malformed); +ADD_CASES("BM_malformed", + {{"", true, + "The benchmark didn't run, nor was it explicitly skipped. Please " + "call 'SkipWithXXX` in your benchmark as appropriate."}}); From bc0989adee868d44c1e3c8ea91e11119c47c6007 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 1 May 2025 17:32:16 +0300 Subject: [PATCH 342/561] Detect and report ASLR status (#1977) * Detect and report ASLR status Theoretically, we could just disable ASLR in `main()`, but that seems to be disallowed by default by some other security features. Refs. https://github.com/google/benchmark/issues/461 * Add a note about ASLR on other OS. --- docs/reducing_variance.md | 24 ++++++++++++++++++++++++ include/benchmark/benchmark.h | 3 +++ src/json_reporter.cc | 8 ++++++++ src/reporter.cc | 6 ++++++ src/sysinfo.cc | 17 ++++++++++++++++- 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/docs/reducing_variance.md b/docs/reducing_variance.md index 105f96e769..acc1421cfa 100644 --- a/docs/reducing_variance.md +++ b/docs/reducing_variance.md @@ -39,6 +39,30 @@ The benchmarks you subsequently run will have less variance. +## Disabling ASLR + +If you see this error: + +``` +***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. +``` + +you might want to disable the ASLR security hardening feature while running the +benchmark. + +To globally disable ASLR on Linux, run +``` +echo 0 > /proc/sys/kernel/randomize_va_space +``` + +To run a single benchmark with ASLR disabled on Linux, do: +``` +setarch `uname -m` -R ./a_benchmark +``` + +Note that for the information on how to disable ASLR on other operating systems, +please refer to their documentation. + ## Reducing Variance in Benchmarks The Linux CPU frequency governor [discussed diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 188377ac48..9e4347b20c 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1731,7 +1731,10 @@ struct BENCHMARK_EXPORT CPUInfo { // Adding Struct for System Information struct BENCHMARK_EXPORT SystemInfo { + enum class ASLR { UNKNOWN, ENABLED, DISABLED }; + std::string name; + ASLR ASLRStatus; static const SystemInfo& Get(); private: diff --git a/src/json_reporter.cc b/src/json_reporter.cc index fe34c0786f..deff77e9ac 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -144,6 +144,14 @@ bool JSONReporter::ReportContext(const Context& context) { << ",\n"; } + const SystemInfo& sysinfo = context.sys_info; + if (SystemInfo::ASLR::UNKNOWN != sysinfo.ASLRStatus) { + out << indent + << FormatKV("aslr_enabled", + sysinfo.ASLRStatus == SystemInfo::ASLR::ENABLED) + << ",\n"; + } + out << indent << "\"caches\": [\n"; indent = std::string(6, ' '); std::string cache_indent(8, ' '); diff --git a/src/reporter.cc b/src/reporter.cc index 1f19ff9c05..71926b15e9 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -88,6 +88,12 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, "overhead.\n"; } + const SystemInfo &sysinfo = context.sys_info; + if (SystemInfo::ASLR::ENABLED == sysinfo.ASLRStatus) { + Out << "***WARNING*** ASLR is enabled, the results may have unreproducible " + "noise in them.\n"; + } + #ifndef NDEBUG Out << "***WARNING*** Library was built as DEBUG. Timings may be " "affected.\n"; diff --git a/src/sysinfo.cc b/src/sysinfo.cc index bf2fee85fc..90559b503b 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -54,6 +54,10 @@ #include #endif +#if defined(BENCHMARK_OS_LINUX) +#include +#endif + #include #include #include @@ -493,6 +497,17 @@ std::string GetSystemName() { #endif // Catch-all POSIX block. } +SystemInfo::ASLR GetASLR() { +#ifdef BENCHMARK_OS_LINUX + const auto curr_personality = personality(0xffffffff); + return (curr_personality & ADDR_NO_RANDOMIZE) ? SystemInfo::ASLR::DISABLED + : SystemInfo::ASLR::ENABLED; +#else + // FIXME: support detecting ASLR on other OS. + return SystemInfo::ASLR::UNKNOWN; +#endif +} + int GetNumCPUsImpl() { #ifdef BENCHMARK_OS_WINDOWS SYSTEM_INFO sysinfo; @@ -881,5 +896,5 @@ const SystemInfo& SystemInfo::Get() { return *info; } -SystemInfo::SystemInfo() : name(GetSystemName()) {} +SystemInfo::SystemInfo() : name(GetSystemName()), ASLRStatus(GetASLR()) {} } // end namespace benchmark From f02794a8bda1295ed7a6c99615f8b79e6188d7f8 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 1 May 2025 19:34:09 +0300 Subject: [PATCH 343/561] Automatic ASLR disablement (#1978) While ASLR is a useful security hardening feature, it introduces unreproducible noise into benchmarks, and we really really really don't want any noise, especially easily avoidable one. Unless prevented by some other security hardening, we can disable ASLR for the current process, and restart it, thus eliminating this noise. Fixes https://github.com/google/benchmark/issues/461 --- bindings/python/google_benchmark/__init__.py | 2 ++ docs/reducing_variance.md | 11 +++++++ docs/user_guide.md | 1 + include/benchmark/benchmark.h | 4 +++ src/benchmark.cc | 33 ++++++++++++++++++++ test/benchmark_min_time_flag_iters_test.cc | 2 ++ test/benchmark_min_time_flag_time_test.cc | 2 ++ test/benchmark_setup_teardown_test.cc | 2 ++ test/complexity_test.cc | 5 ++- test/diagnostics_test.cc | 1 + test/display_aggregates_only_test.cc | 2 ++ test/donotoptimize_test.cc | 4 ++- test/filter_test.cc | 2 ++ test/internal_threading_test.cc | 6 +++- test/manual_threading_test.cc | 1 + test/memory_manager_test.cc | 1 + test/perf_counters_test.cc | 1 + test/profiler_manager_iterations_test.cc | 1 + test/profiler_manager_test.cc | 1 + test/register_benchmark_test.cc | 1 + test/repetitions_test.cc | 5 ++- test/report_aggregates_only_test.cc | 1 + test/reporter_output_test.cc | 5 ++- test/skip_with_error_test.cc | 1 + test/spec_arg_test.cc | 2 ++ test/spec_arg_verbosity_test.cc | 2 ++ test/user_counters_tabular_test.cc | 5 ++- test/user_counters_test.cc | 5 ++- test/user_counters_thousands_test.cc | 5 ++- 29 files changed, 106 insertions(+), 8 deletions(-) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index e6665135eb..41517b2a8c 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -137,6 +137,8 @@ def main(argv=None): return app.run(_run_benchmarks, argv=argv, flags_parser=_flags_parser) +# FIXME: can we rerun with disabled ASLR? + # Methods for use with custom main function. initialize = _benchmark.Initialize run_benchmarks = _benchmark.RunSpecifiedBenchmarks diff --git a/docs/reducing_variance.md b/docs/reducing_variance.md index acc1421cfa..e604c66cd5 100644 --- a/docs/reducing_variance.md +++ b/docs/reducing_variance.md @@ -50,6 +50,17 @@ If you see this error: you might want to disable the ASLR security hardening feature while running the benchmark. +The simplest way is to add +``` +benchmark::MaybeReenterWithoutASLR(argc, argv); +``` +as the first line of your `main()` function. It will try to disable ASLR +for the current processor, and, if successful, re-execute the binary. +Note that `personality(2)` may be forbidden by e.g. seccomp (which happens +by default if you are running in a Docker container). + +Note that if you link to `benchmark_main` already does that for you. + To globally disable ASLR on Linux, run ``` echo 0 > /proc/sys/kernel/randomize_va_space diff --git a/docs/user_guide.md b/docs/user_guide.md index 3b8f9d54c1..ae8e1251bd 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1268,6 +1268,7 @@ For Example: auto BM_test = [](benchmark::State& st, auto Inputs) { /* ... */ }; int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); for (auto& test_input : { /* ... */ }) benchmark::RegisterBenchmark(test_input.name(), BM_test, test_input); benchmark::Initialize(&argc, argv); diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 9e4347b20c..f455e05d78 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -40,6 +40,7 @@ BENCHMARK(BM_StringCopy); // my_unittest --benchmark_filter=String // my_unittest --benchmark_filter='Copy|Creation' int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); benchmark::Shutdown(); @@ -334,6 +335,8 @@ using callback_function = std::function; // Default number of minimum benchmark running time in seconds. const char kDefaultMinTimeStr[] = "0.5s"; +BENCHMARK_EXPORT void MaybeReenterWithoutASLR(int, char**); + // Returns the version of the library. BENCHMARK_EXPORT std::string GetBenchmarkVersion(); @@ -1687,6 +1690,7 @@ class Fixture : public internal::Benchmark { // Note the workaround for Hexagon simulator passing argc != 0, argv = NULL. #define BENCHMARK_MAIN() \ int main(int argc, char** argv) { \ + benchmark::MaybeReenterWithoutASLR(argc, argv); \ char arg0_default[] = "benchmark"; \ char* args_default = reinterpret_cast(arg0_default); \ if (!argv) { \ diff --git a/src/benchmark.cc b/src/benchmark.cc index 925a38ff22..48a2accdf9 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -26,6 +26,10 @@ #include #endif +#ifdef BENCHMARK_OS_LINUX +#include +#endif + #include #include #include @@ -813,6 +817,35 @@ int InitializeStreams() { } // end namespace internal +void MaybeReenterWithoutASLR(int /*argc*/, char** argv) { + // On e.g. Hexagon simulator, argv may be NULL. + if (!argv) return; + +#ifdef BENCHMARK_OS_LINUX + const auto curr_personality = personality(0xffffffff); + + // We should never fail to read-only query the current personality, + // but let's be cautious. + if (curr_personality == -1) return; + + // If ASLR is already disabled, we have nothing more to do. + if (curr_personality & ADDR_NO_RANDOMIZE) return; + + // Try to change the personality to disable ASLR. + const auto prev_personality = personality( + static_cast(curr_personality) | ADDR_NO_RANDOMIZE); + + // Have we failed to change the personality? That may happen. + if (prev_personality == -1) return; + + execv(argv[0], argv); + // The exec() functions return only if an error has occurred, + // in which case we want to just continue as-is. +#else + return; +#endif +} + std::string GetBenchmarkVersion() { #ifdef BENCHMARK_VERSION return {BENCHMARK_VERSION}; diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index a5964f10b3..5e25aa9ee7 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -44,6 +44,8 @@ static void BM_MyBench(benchmark::State& state) { BENCHMARK(BM_MyBench); int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + // Make a fake argv and append the new --benchmark_min_time= to it. int fake_argc = argc + 1; std::vector fake_argv(static_cast(fake_argc)); diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index 0a136fa088..8d221e41ba 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -69,6 +69,8 @@ static void BM_MyBench(benchmark::State& state) { BENCHMARK(BM_MyBench); int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + // Make a fake argv and append the new --benchmark_min_time= to it. int fake_argc = argc + 1; std::vector fake_argv(static_cast(fake_argc)); diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index bf45fd10e9..53695e9886 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -134,6 +134,8 @@ BENCHMARK(BM_WithRep) ->Repetitions(4); int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + benchmark::Initialize(&argc, argv); size_t ret = benchmark::RunSpecifiedBenchmarks("."); diff --git a/test/complexity_test.cc b/test/complexity_test.cc index f208cb3a0b..23c5f3e519 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -269,4 +269,7 @@ ADD_COMPLEXITY_CASES(complexity_capture_name, complexity_capture_name + "_BigO", // --------------------------- TEST CASES END ------------------------------ // // ========================================================================= // -int main(int argc, char *argv[]) { RunOutputTests(argc, argv); } +int main(int argc, char *argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index 61de28620a..e930f024e9 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -94,6 +94,7 @@ int main(int argc, char* argv[]) { (void)argc; (void)argv; #else + benchmark::MaybeReenterWithoutASLR(argc, argv); benchmark::internal::GetAbortHandler() = &TestHandler; benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); diff --git a/test/display_aggregates_only_test.cc b/test/display_aggregates_only_test.cc index 6ad65e7f51..1d3b6cd2df 100644 --- a/test/display_aggregates_only_test.cc +++ b/test/display_aggregates_only_test.cc @@ -17,6 +17,8 @@ void BM_SummaryRepeat(benchmark::State& state) { BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->DisplayAggregatesOnly(); int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + const std::string output = GetFileReporterOutput(argc, argv); if (SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3") != 7 || diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc index 5c9a4583de..7571cf445e 100644 --- a/test/donotoptimize_test.cc +++ b/test/donotoptimize_test.cc @@ -26,7 +26,9 @@ struct BitRef { BitRef(int i, unsigned char& b) : index(i), byte(b) {} }; -int main(int /*unused*/, char* /*unused*/[]) { +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + // this test verifies compilation of DoNotOptimize() for some types char buffer1[1] = ""; diff --git a/test/filter_test.cc b/test/filter_test.cc index a931a68e0f..0a4a1df6c5 100644 --- a/test/filter_test.cc +++ b/test/filter_test.cc @@ -70,6 +70,8 @@ static void BM_FooBa(benchmark::State& state) { BENCHMARK(BM_FooBa); int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + bool list_only = false; for (int i = 0; i < argc; ++i) { list_only |= std::string(argv[i]).find("--benchmark_list_tests") != diff --git a/test/internal_threading_test.cc b/test/internal_threading_test.cc index 6984ff853b..d2897e7212 100644 --- a/test/internal_threading_test.cc +++ b/test/internal_threading_test.cc @@ -183,4 +183,8 @@ BENCHMARK(BM_MainThreadAndWorkerThread) // ---------------------------- TEST CASES END ----------------------------- // // ========================================================================= // -int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + + RunOutputTests(argc, argv); +} diff --git a/test/manual_threading_test.cc b/test/manual_threading_test.cc index e85d495620..b3252ec16e 100644 --- a/test/manual_threading_test.cc +++ b/test/manual_threading_test.cc @@ -167,6 +167,7 @@ BENCHMARK(BM_ManualThreading) // ========================================================================= // int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); benchmark::Shutdown(); diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index ebb72b0341..f9b9021892 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -40,6 +40,7 @@ ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"}, ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}}); int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); std::unique_ptr mm(new TestMemoryManager()); benchmark::RegisterMemoryManager(mm.get()); diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index 3cc593e629..8aa3a7b632 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -79,6 +79,7 @@ CHECK_BENCHMARK_RESULTS("BM_WithoutPauseResume", &SaveInstrCountWithoutResume); CHECK_BENCHMARK_RESULTS("BM_WithPauseResume", &SaveInstrCountWithResume); int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); if (!benchmark::internal::PerfCounters::kSupported) { return 0; } diff --git a/test/profiler_manager_iterations_test.cc b/test/profiler_manager_iterations_test.cc index 407d33b994..af1052f7a5 100644 --- a/test/profiler_manager_iterations_test.cc +++ b/test/profiler_manager_iterations_test.cc @@ -35,6 +35,7 @@ static void BM_MyBench(benchmark::State& state) { BENCHMARK(BM_MyBench); int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); // Make a fake argv and append the new --benchmark_profiler_iterations= // to it. int fake_argc = argc + 1; diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc index 21f2f1dc03..75a2aaa50b 100644 --- a/test/profiler_manager_test.cc +++ b/test/profiler_manager_test.cc @@ -40,6 +40,7 @@ ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"}, ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}}); int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); std::unique_ptr pm(new TestProfilerManager()); benchmark::RegisterProfilerManager(pm.get()); diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index 1a188142de..e91ba97663 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -184,6 +184,7 @@ void RunTestTwo() { } int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); benchmark::Initialize(&argc, argv); RunTestOne(); diff --git a/test/repetitions_test.cc b/test/repetitions_test.cc index 569777d5f9..9a7dcc3015 100644 --- a/test/repetitions_test.cc +++ b/test/repetitions_test.cc @@ -211,4 +211,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_stddev\",%csv_report$"}}); // --------------------------- TEST CASES END ------------------------------ // // ========================================================================= // -int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} diff --git a/test/report_aggregates_only_test.cc b/test/report_aggregates_only_test.cc index 47da503588..d907559073 100644 --- a/test/report_aggregates_only_test.cc +++ b/test/report_aggregates_only_test.cc @@ -17,6 +17,7 @@ void BM_SummaryRepeat(benchmark::State& state) { BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->ReportAggregatesOnly(); int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); const std::string output = GetFileReporterOutput(argc, argv); if (SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3") != 4 || diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index bd50a255b2..58860ca0b0 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -1133,4 +1133,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_CSV_Format\",,,,,,,,true,\"\"\"freedom\"\"\"$"}}); // --------------------------- TEST CASES END ------------------------------ // // ========================================================================= // -int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 1056f86191..7553eba3f9 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -183,6 +183,7 @@ ADD_CASES("BM_error_while_paused", {{"/1/threads:1", true, "error message"}, {"/2/threads:8", false, ""}}); int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); benchmark::Initialize(&argc, argv); TestReporter test_reporter; diff --git a/test/spec_arg_test.cc b/test/spec_arg_test.cc index 06aafbeb9b..cec5c32ee8 100644 --- a/test/spec_arg_test.cc +++ b/test/spec_arg_test.cc @@ -55,6 +55,8 @@ static void BM_Chosen(benchmark::State& state) { BENCHMARK(BM_Chosen); int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + const std::string flag = "BM_NotChosen"; // Verify that argv specify --benchmark_filter=BM_NotChosen. diff --git a/test/spec_arg_verbosity_test.cc b/test/spec_arg_verbosity_test.cc index 8f8eb6d37c..43dfda9d55 100644 --- a/test/spec_arg_verbosity_test.cc +++ b/test/spec_arg_verbosity_test.cc @@ -12,6 +12,8 @@ static void BM_Verbosity(benchmark::State& state) { BENCHMARK(BM_Verbosity); int main(int argc, char** argv) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + const int32_t flagv = 42; // Verify that argv specify --v=42. diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index d26120e082..0046210bcf 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -560,4 +560,7 @@ CHECK_BENCHMARK_RESULTS("BM_CounterSet2_Tabular", &CheckSet2); // --------------------------- TEST CASES END ------------------------------ // // ========================================================================= // -int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index d3fd4a6eab..910f9300b2 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -565,4 +565,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_kAvgIterationsRate", // --------------------------- TEST CASES END ------------------------------ // // ========================================================================= // -int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} diff --git a/test/user_counters_thousands_test.cc b/test/user_counters_thousands_test.cc index dd4efd4f44..4f341db5da 100644 --- a/test/user_counters_thousands_test.cc +++ b/test/user_counters_thousands_test.cc @@ -184,4 +184,7 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Thousands", &CheckThousands); // --------------------------- TEST CASES END ------------------------------ // // ========================================================================= // -int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} From bd9bb643f4fc4918a74320eeaf32db32d8986ab4 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 6 May 2025 10:32:40 +0200 Subject: [PATCH 344/561] dev: Update pre-commit hooks (#1979) From a run of `pre-commit autoupdate`. --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 44aa3bde42..49d544e3ff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 8.0.1 + rev: 8.0.3 hooks: - id: buildifier - id: buildifier-lint @@ -11,7 +11,7 @@ repos: types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.6 + rev: v0.11.8 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] From 299e5928955cc62af9968370293b916f5130916f Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 7 May 2025 09:39:33 +0100 Subject: [PATCH 345/561] bump to v1.9.3 to prepare a release --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fcbba0d03c..959cbef9ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.13...3.22) -project (benchmark VERSION 1.9.2 LANGUAGES CXX) +project (benchmark VERSION 1.9.3 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 37d9c40078..e468ab820f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.9.2", + version = "1.9.3", ) bazel_dep(name = "bazel_skylib", version = "1.7.1") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 41517b2a8c..93a4354e28 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -50,7 +50,7 @@ def my_benchmark(state): oNSquared as oNSquared, ) -__version__ = "1.9.2" +__version__ = "1.9.3" class __OptionMaker: From afd9c342fb8a840117c9a3e3e85c1ecff036bc8f Mon Sep 17 00:00:00 2001 From: Andrewyuan34 Date: Fri, 9 May 2025 00:19:10 -0400 Subject: [PATCH 346/561] Update build instructions for Visual Studio (#1980) --- docs/platform_specific_build_instructions.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/platform_specific_build_instructions.md b/docs/platform_specific_build_instructions.md index 2d5d6c47ee..5c1439d0a9 100644 --- a/docs/platform_specific_build_instructions.md +++ b/docs/platform_specific_build_instructions.md @@ -15,22 +15,26 @@ On QNX, the pthread library is part of libc and usually included automatically [`pthread_create()`](https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.lib_ref/topic/p/pthread_create.html)). There's no separate pthread library to link. -## Building with Visual Studio 2015 or 2017 +## Building with Visual Studio 2015, 2017 or 2022 The `shlwapi` library (`-lshlwapi`) is required to support a call to `CPUInfo` which reads the registry. Either add `shlwapi.lib` under `[ Configuration Properties > Linker > Input ]`, or use the following: ``` // Alternatively, can add libraries using linker options. + +// First, Add the path to the generated library files (directory containing the `benchmark.lib`) in `[Configuration Properties > Linker > General > Additional Library Directories]`. Then do the following: #ifdef _WIN32 #pragma comment ( lib, "Shlwapi.lib" ) #ifdef _DEBUG -#pragma comment ( lib, "benchmarkd.lib" ) +#pragma comment ( lib, "benchmark.lib" ) #else #pragma comment ( lib, "benchmark.lib" ) #endif #endif ``` +When using the static library, make sure to add `BENCHMARK_STATIC_DEFINE` under `[Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions]` + Can also use the graphical version of CMake: * Open `CMake GUI`. * Under `Where to build the binaries`, same path as source plus `build`. From f921cfb4af82aa9dac72a909b764153789499d6b Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 12 May 2025 13:10:05 +0300 Subject: [PATCH 347/561] `MaybeReenterWithoutASLR()`: be more cautious about argument types (#1983) It seems, on android the argument is narrower than on linux. Let's try to support that while not introducing any explicit lossy casts. Fixes https://github.com/google/benchmark/issues/1982 --- src/benchmark.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 48a2accdf9..9a98f889db 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -815,6 +815,12 @@ int InitializeStreams() { return 0; } +template +std::make_unsigned_t get_as_unsigned(T v) { + using UnsignedT = std::make_unsigned_t; + return static_cast(v); +} + } // end namespace internal void MaybeReenterWithoutASLR(int /*argc*/, char** argv) { @@ -829,11 +835,12 @@ void MaybeReenterWithoutASLR(int /*argc*/, char** argv) { if (curr_personality == -1) return; // If ASLR is already disabled, we have nothing more to do. - if (curr_personality & ADDR_NO_RANDOMIZE) return; + if (internal::get_as_unsigned(curr_personality) & ADDR_NO_RANDOMIZE) return; // Try to change the personality to disable ASLR. - const auto prev_personality = personality( - static_cast(curr_personality) | ADDR_NO_RANDOMIZE); + const auto proposed_personality = + internal::get_as_unsigned(curr_personality) | ADDR_NO_RANDOMIZE; + const auto prev_personality = personality(proposed_personality); // Have we failed to change the personality? That may happen. if (prev_personality == -1) return; From 4995099c4f6bd751432ebb167a6709b455a3dc93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 May 2025 21:15:37 +0200 Subject: [PATCH 348/561] Fix `MaybeReenterWithoutASLR()` in docker (#1985) In some docker configurations the `personality()` function may return inconsistent results. Double check if the persona has been updated before reentering, otherwise we risk infinite loop. Fixes https://github.com/google/benchmark/issues/1984. --- src/benchmark.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/benchmark.cc b/src/benchmark.cc index 9a98f889db..8672c8a94f 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -845,6 +845,13 @@ void MaybeReenterWithoutASLR(int /*argc*/, char** argv) { // Have we failed to change the personality? That may happen. if (prev_personality == -1) return; + // Make sure the parsona has been updated with the no-ASLR flag, + // otherwise we will try to reenter infinitely. + // This seems impossible, but can happen in some docker configurations. + const auto new_personality = personality(0xffffffff); + if ((internal::get_as_unsigned(new_personality) & ADDR_NO_RANDOMIZE) == 0) + return; + execv(argv[0], argv); // The exec() functions return only if an error has occurred, // in which case we want to just continue as-is. From 3231850f55e3b76ca02b405e6da69bd8045a2bcc Mon Sep 17 00:00:00 2001 From: Xiaochuan Ye Date: Mon, 19 May 2025 23:36:32 +0800 Subject: [PATCH 349/561] fix: enable running in WebAssembly without filesystem (#1956) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/sysinfo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 90559b503b..60e9e5c219 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -439,7 +439,7 @@ std::vector GetCacheSizes() { return GetCacheSizesWindows(); #elif defined(BENCHMARK_OS_QNX) return GetCacheSizesQNX(); -#elif defined(BENCHMARK_OS_QURT) +#elif defined(BENCHMARK_OS_QURT) || defined(__EMSCRIPTEN__) return std::vector(); #else return GetCacheSizesFromKVFS(); From 64151f3a1a8db5e8cb1bcef1b10c5e240a97a16f Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 19 May 2025 17:44:07 +0200 Subject: [PATCH 350/561] wheels: Build Linux ARM wheels natively on ARM runners (#1969) * actions: Update Linux Docker Bazel install script to version 8.2.0 Bazel 8.2.0 was released on April 14, earlier this week. * wheels: Build all wheels on native runner platforms Since Ubuntu on ARM runners are now available, we can build wheels directly on the host machines instead of going the slow way of QEMU virtualization. --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/install_bazel.sh | 2 +- .github/workflows/wheels.yml | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/install_bazel.sh b/.github/install_bazel.sh index 1b0d63c98e..a1693b87ea 100644 --- a/.github/install_bazel.sh +++ b/.github/install_bazel.sh @@ -4,7 +4,7 @@ if ! bazel version; then arch="arm64" fi echo "Downloading $arch Bazel binary from GitHub releases." - curl -L -o $HOME/bin/bazel --create-dirs "https://github.com/bazelbuild/bazel/releases/download/7.1.1/bazel-7.1.1-linux-$arch" + curl -L -o $HOME/bin/bazel --create-dirs "https://github.com/bazelbuild/bazel/releases/download/8.2.0/bazel-8.2.0-linux-$arch" chmod +x $HOME/bin/bazel else # Bazel is installed for the correct architecture diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d24db9c7cc..4f0fa877a7 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -35,8 +35,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-13, macos-14, windows-latest] - + os: [ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-14, windows-latest] steps: - name: Check out Google Benchmark uses: actions/checkout@v4 @@ -49,20 +48,13 @@ jobs: python-version: "3.12" - run: pip install --upgrade pip uv - - name: Set up QEMU - if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v3 - with: - platforms: all - - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.22.0 + uses: pypa/cibuildwheel@v2.23.2 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" CIBW_SKIP: "*-musllinux_*" - CIBW_ARCHS_LINUX: auto64 aarch64 - CIBW_ARCHS_WINDOWS: auto64 + CIBW_ARCHS: auto64 CIBW_BEFORE_ALL_LINUX: bash .github/install_bazel.sh # Grab the rootless Bazel installation inside the container. CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin From eddb0241389718a23a42db6af5f0164b6e0139af Mon Sep 17 00:00:00 2001 From: dominic hamon Date: Mon, 19 May 2025 16:45:45 +0100 Subject: [PATCH 351/561] bump to v1.9.4 --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 959cbef9ef..219b151142 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.13...3.22) -project (benchmark VERSION 1.9.3 LANGUAGES CXX) +project (benchmark VERSION 1.9.4 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index e468ab820f..7390c98ad3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.9.3", + version = "1.9.4", ) bazel_dep(name = "bazel_skylib", version = "1.7.1") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 93a4354e28..44a54f5165 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -50,7 +50,7 @@ def my_benchmark(state): oNSquared as oNSquared, ) -__version__ = "1.9.3" +__version__ = "1.9.4" class __OptionMaker: From 0d522831cffca19cd599fb4cb31b2893083c7444 Mon Sep 17 00:00:00 2001 From: Arseniy Terekhin Date: Wed, 21 May 2025 11:21:35 +0300 Subject: [PATCH 352/561] python binding: add range check (#1990) fixes segmentation fault in ```import google_benchmark as benchmark @benchmark.register def av_test(state): state.range(9) benchmark.main() ``` --- bindings/python/google_benchmark/benchmark.cc | 10 +++++++++- include/benchmark/benchmark.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index a935822536..0415b2b68b 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -167,7 +167,15 @@ NB_MODULE(_benchmark, m) { .def_prop_rw("items_processed", &State::items_processed, &State::SetItemsProcessed) .def("set_label", &State::SetLabel) - .def("range", &State::range, nb::arg("pos") = 0) + .def( + "range", + [](const State& state, std::size_t pos = 0) -> int64_t { + if (pos < state.range_size()) { + return state.range(pos); + } + throw nb::index_error("pos is out of range"); + }, + nb::arg("pos") = 0) .def_prop_ro("iterations", &State::iterations) .def_prop_ro("name", &State::name) .def_rw("counters", &State::counters) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index f455e05d78..921676f30e 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -956,6 +956,8 @@ class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { BENCHMARK_ALWAYS_INLINE std::string name() const { return name_; } + size_t range_size() const { return range_.size(); } + private: // items we expect on the first cache line (ie 64 bytes of the struct) // When total_iterations_ is 0, KeepRunning() and friends will return false. From d24860fa89fc376b8a601af1b9ce7979067c8d5f Mon Sep 17 00:00:00 2001 From: Arseniy Terekhin Date: Wed, 21 May 2025 14:44:13 +0300 Subject: [PATCH 353/561] fix: resolve editable installation issue for python package (#1989) Before this `pip install -e .` produced ` error: [Errno 2] No such file or directory: '/tmp/tmpi02jtn4q.build-lib/google_benchmark/_benchmark.pyi'` --- setup.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3c0269b199..ed8c396290 100644 --- a/setup.py +++ b/setup.py @@ -131,7 +131,11 @@ def bazel_build(self, ext: BazelExtension) -> None: # noqa: C901 pkgname = "google_benchmark" pythonroot = Path("bindings") / "python" / "google_benchmark" srcdir = temp_path / "bazel-bin" / pythonroot - libdir = Path(self.build_lib) / pkgname + if not self.inplace: + libdir = Path(self.build_lib) / pkgname + else: + build_py = self.get_finalized_command("build_py") + libdir = build_py.get_package_dir(pkgname) for root, dirs, files in os.walk(srcdir, topdown=True): # exclude runfiles directories and children. dirs[:] = [d for d in dirs if "runfiles" not in d] From 176ad6c20c2a3a4a2613e041b90b76b4102aae3d Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 23 May 2025 18:39:03 +0800 Subject: [PATCH 354/561] Add deprecation warnings for MSVC (#1993) * Add deprecation warnings for MSVC * Split `DoNotOptimize` overloads for MSVC --- include/benchmark/benchmark.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 921676f30e..661f9d370e 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -239,6 +239,16 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); _Pragma("diagnostic push") \ _Pragma("diag_suppress deprecated_entity_with_custom_message") #define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("diagnostic pop") +#elif defined(_MSC_VER) +#define BENCHMARK_BUILTIN_EXPECT(x, y) x +#define BENCHMARK_DEPRECATED_MSG(msg) __declspec(deprecated(msg)) +#define BENCHMARK_WARNING_MSG(msg) \ + __pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING( \ + __LINE__) ") : warning note: " msg)) +#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) +#define BENCHMARK_RESTORE_DEPRECATED_WARNING __pragma(warning(pop)) #else #define BENCHMARK_BUILTIN_EXPECT(x, y) x #define BENCHMARK_DEPRECATED_MSG(msg) @@ -611,6 +621,17 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { _ReadWriteBarrier(); } +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { + internal::UseCharPointer(&reinterpret_cast(value)); + _ReadWriteBarrier(); +} + +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { + internal::UseCharPointer(&reinterpret_cast(value)); + _ReadWriteBarrier(); +} #else template inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { From ce80955d26de0b7c888e5629b2e6509f91498062 Mon Sep 17 00:00:00 2001 From: Prithvi P Rao <130847740+Proxihox@users.noreply.github.com> Date: Fri, 23 May 2025 19:50:32 +0530 Subject: [PATCH 355/561] [doc] Added nice to reducing_variance (#1994) * docs:added nice to reducing_variance * Added self as contributor --- AUTHORS | 1 + CONTRIBUTORS | 1 + docs/reducing_variance.md | 15 ++++++++++----- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 2170e46fd4..a6505d6388 100644 --- a/AUTHORS +++ b/AUTHORS @@ -56,6 +56,7 @@ Norman Heino Oleksandr Sochka Ori Livneh Paul Redmond +Prithvi Rao Radoslav Yovchev Raghu Raja Rainer Orth diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 54aba7b56d..18a49a165f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -80,6 +80,7 @@ Ori Livneh Pascal Leroy Paul Redmond Pierre Phaneuf +Prithvi Rao Radoslav Yovchev Raghu Raja Rainer Orth diff --git a/docs/reducing_variance.md b/docs/reducing_variance.md index e604c66cd5..364f4af15b 100644 --- a/docs/reducing_variance.md +++ b/docs/reducing_variance.md @@ -105,23 +105,28 @@ Linux workstation are: 1. Use the performance governor as [discussed above](user_guide#disabling-cpu-frequency-scaling). -1. Disable processor boosting by: +2. Disable processor boosting by: ```sh echo 0 | sudo tee /sys/devices/system/cpu/cpufreq/boost ``` See the Linux kernel's [boost.txt](https://www.kernel.org/doc/Documentation/cpu-freq/boost.txt) for more information. -2. Set the benchmark program's task affinity to a fixed cpu. For example: +3. Set the benchmark program's task affinity to a fixed cpu. For example: ```sh taskset -c 0 ./mybenchmark ``` -3. Disabling Hyperthreading/SMT. This can be done in the Bios or using the +4. Increase the program's scheduling priority to minimize context switches using `nice` or `chrt`: + ```sh + sudo nice -n -20 ./mybenchmark + sudo chrt -f 80 ./mybenchmark + ``` +5. Disabling Hyperthreading/SMT. This can be done in the Bios or using the `/sys` file system (see the LLVM project's [Benchmarking tips](https://llvm.org/docs/Benchmarking.html)). -4. Close other programs that do non-trivial things based on timers, such as +6. Close other programs that do non-trivial things based on timers, such as your web browser, desktop environment, etc. -5. Reduce the working set of your benchmark to fit within the L1 cache, but +7. Reduce the working set of your benchmark to fit within the L1 cache, but do be aware that this may lead you to optimize for an unrealistic situation. From 1b721bbeff0497dfe8e3432b6b7ec75c92b4631b Mon Sep 17 00:00:00 2001 From: Shashank Thakur <124647775+xshthkr@users.noreply.github.com> Date: Fri, 6 Jun 2025 16:15:56 +0200 Subject: [PATCH 356/561] Fix bug: link Shlwapi in Libs.private for Windows (#1996) * link Shlwapi in Libs.private for Windows * Add self as contributor --- AUTHORS | 1 + CONTRIBUTORS | 1 + src/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index a6505d6388..3e593aaf48 100644 --- a/AUTHORS +++ b/AUTHORS @@ -63,6 +63,7 @@ Rainer Orth Roman Lebedev Sayan Bhattacharjee Shapr3D +Shashank Thakur Shuo Chen Staffan Tjernstrom Steinar H. Gunderson diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 18a49a165f..5c68838bd7 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -89,6 +89,7 @@ Ray Glover Robert Guo Roman Lebedev Sayan Bhattacharjee +Shashank Thakur Shuo Chen Steven Wan Tobias Schmidt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9fb305a0e4..9288c9857c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,6 +62,7 @@ endif(HAVE_LIB_RT) # We need extra libraries on Windows if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") target_link_libraries(benchmark PRIVATE shlwapi) + set(BENCHMARK_PRIVATE_LINK_LIBRARIES -lShlwapi) endif() # We need extra libraries on Solaris From d9ed709886e0fae40fe6932d652d1b7f47491985 Mon Sep 17 00:00:00 2001 From: Shashank Thakur <124647775+xshthkr@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:00:58 +0200 Subject: [PATCH 357/561] Refactor: derive pkg-config info to link static libraries (#1998) --- src/CMakeLists.txt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9288c9857c..fe7325365f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,13 +62,11 @@ endif(HAVE_LIB_RT) # We need extra libraries on Windows if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") target_link_libraries(benchmark PRIVATE shlwapi) - set(BENCHMARK_PRIVATE_LINK_LIBRARIES -lShlwapi) endif() # We need extra libraries on Solaris if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS") target_link_libraries(benchmark PRIVATE kstat) - set(BENCHMARK_PRIVATE_LINK_LIBRARIES -lkstat) endif() if (NOT BUILD_SHARED_LIBS) @@ -110,6 +108,20 @@ write_basic_package_version_file( "${version_config}" VERSION ${GENERIC_LIB_VERSION} COMPATIBILITY SameMajorVersion ) +# Derive private link libraries from target +if(NOT BUILD_SHARED_LIBS) + get_target_property(LINK_LIBS benchmark LINK_LIBRARIES) + if(LINK_LIBS) + set(BENCHMARK_PRIVATE_LINK_LIBRARIES "") + foreach(LIB IN LISTS LINK_LIBS) + if(NOT TARGET "${LIB}" AND LIB MATCHES "^[a-zA-Z0-9_.-]+$") + list(APPEND BENCHMARK_PRIVATE_LINK_LIBRARIES "-l${LIB}") + endif() + endforeach() + string(JOIN " " BENCHMARK_PRIVATE_LINK_LIBRARIES ${BENCHMARK_PRIVATE_LINK_LIBRARIES}) + endif() +endif() + configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY) configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark_main.pc.in" "${pkg_config_main}" @ONLY) From 7f727750846552fb507d778b2b125dd6d32061bf Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Thu, 12 Jun 2025 16:54:21 +0200 Subject: [PATCH 358/561] python: Update to cibuildwheel 3.0 (#1999) Includes an implicit update to manylinux_2_28 (i.e., for systems with a glibc version >=2.28). We now set the MacOS deployment target dynamically based on the runner image to avoid a warning on the MacOS Intel runner. --- .github/workflows/wheels.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4f0fa877a7..a374fa194f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -46,10 +46,11 @@ jobs: name: Install Python 3.12 with: python-version: "3.12" - - run: pip install --upgrade pip uv + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v6 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v2.23.2 + uses: pypa/cibuildwheel@v3.0.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" @@ -60,7 +61,7 @@ jobs: CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py # unused by Bazel, but needed explicitly by delocate on MacOS. - MACOSX_DEPLOYMENT_TARGET: "10.14" + MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-13' && 10.14 || 11.0 }} - name: Upload Google Benchmark ${{ matrix.os }} wheels uses: actions/upload-artifact@v4 From f30ba8b9932840a9773311e65bf1b00f403b7646 Mon Sep 17 00:00:00 2001 From: Tomasetti Romin Date: Fri, 27 Jun 2025 17:18:26 +0200 Subject: [PATCH 359/561] core(perf): use string move constructor for AddCustomContext (#2005) Signed-off-by: romintomasetti --- include/benchmark/benchmark.h | 2 +- src/benchmark.cc | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 661f9d370e..f88f648e79 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -486,7 +486,7 @@ void RegisterProfilerManager(ProfilerManager* profiler_manager); // Add a key-value pair to output as part of the context stanza in the report. BENCHMARK_EXPORT -void AddCustomContext(const std::string& key, const std::string& value); +void AddCustomContext(std::string key, std::string value); namespace internal { class Benchmark; diff --git a/src/benchmark.cc b/src/benchmark.cc index 8672c8a94f..02161f90bb 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -708,11 +708,12 @@ void RegisterProfilerManager(ProfilerManager* manager) { internal::profiler_manager = manager; } -void AddCustomContext(const std::string& key, const std::string& value) { +void AddCustomContext(std::string key, std::string value) { if (internal::global_context == nullptr) { internal::global_context = new std::map(); } - if (!internal::global_context->emplace(key, value).second) { + if (!internal::global_context->emplace(std::move(key), std::move(value)) + .second) { std::cerr << "Failed to add custom context \"" << key << "\" as it already " << "exists with value \"" << value << "\"\n"; } From b20cea674170b2ba45da0dfaf03953cdea473d0d Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 27 Jun 2025 15:26:28 -0400 Subject: [PATCH 360/561] Guard adding intel compiler flag behind check for intel compiler. (#2004) * Guard adding intel compiler flag behind check for intel compiler. For reasons I don't yet fully understand, failing to guard the check for flag -wd654 will cause it to be added to certain clang configurations, and then cause compilation to fail. While exactly why this happens needs investigation, the fix proposed in this patch seems direct and simple enough to apply regardless. * Update CMakeLists.txt Address review comments by reusing intel compiler block. --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 219b151142..b573ead887 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,6 +216,9 @@ else() # See #631 for rationale. add_cxx_compiler_flag(-wd1786) add_cxx_compiler_flag(-fno-finite-math-only) + # ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially + # overridden (because of deprecated overload) + add_cxx_compiler_flag(-wd654) endif() # Disable deprecation warnings for release builds (when -Werror is enabled). if(BENCHMARK_ENABLE_WERROR) @@ -230,9 +233,7 @@ else() add_cxx_compiler_flag(-Wstrict-aliasing) endif() endif() - # ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden - # (because of deprecated overload) - add_cxx_compiler_flag(-wd654) + add_cxx_compiler_flag(-Wthread-safety) if (HAVE_CXX_FLAG_WTHREAD_SAFETY) cxx_feature_check(THREAD_SAFETY_ATTRIBUTES "-DINCLUDE_DIRECTORIES=${PROJECT_SOURCE_DIR}/include") From 053b7483442f7b91848f09bb87b9c5b43882632b Mon Sep 17 00:00:00 2001 From: Max <77984877+GrinlexGH@users.noreply.github.com> Date: Mon, 7 Jul 2025 15:17:56 +0300 Subject: [PATCH 361/561] Update sysinfo.cc to fix compilation on windows (#2008) Fixes #2007 --- src/sysinfo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 60e9e5c219..3977772bfe 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -461,7 +461,7 @@ std::string GetSystemName() { DWCOUNT, NULL, 0, NULL, NULL); str.resize(len); WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, hostname, DWCOUNT, &str[0], - str.size(), NULL, NULL); + static_cast(str.size()), NULL, NULL); #endif return str; #elif defined(BENCHMARK_OS_QURT) From 8516492e880bc26b1b5ba7a5c76b83ca7139761f Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 7 Jul 2025 15:52:59 +0300 Subject: [PATCH 362/561] CI: update available containers (#2009) https://github.com/actions/runner-images/issues/12045 --- .github/workflows/build-and-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 858ea8cce2..4b410d58a3 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -60,7 +60,7 @@ jobs: fail-fast: false matrix: msvc: - - VS-16-2019 + - VS-17-2025 - VS-17-2022 build_type: - Debug @@ -69,9 +69,9 @@ jobs: - shared - static include: - - msvc: VS-16-2019 - os: windows-2019 - generator: 'Visual Studio 16 2019' + - msvc: VS-17-2025 + os: windows-2025 + generator: 'Visual Studio 17 2022' - msvc: VS-17-2022 os: windows-2022 generator: 'Visual Studio 17 2022' From 4e18a0017697fe04fa10d052011b8375e584274b Mon Sep 17 00:00:00 2001 From: mosfet80 <10235105+mosfet80@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:22:48 +0200 Subject: [PATCH 363/561] Update lib pre-commit for ruff (#2010) Changelog: https://github.com/astral-sh/ruff-pre-commit/releases --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 49d544e3ff..86ceaf623d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.8 + rev: v0.11.13 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] From 77c03fbcdcb7f28cd1f65d0e222542ef08ffd277 Mon Sep 17 00:00:00 2001 From: Olga Fadeeva Date: Thu, 24 Jul 2025 19:44:42 +0200 Subject: [PATCH 364/561] Added OpenSSF Scorecard Badge for Security Insights (#2014) * Update CONTRIBUTORS * Update AUTHORS * added openSSF badge into README.md * Create ossf.yml --- .github/workflows/ossf.yml | 21 +++++++++++++++++++++ AUTHORS | 1 + CONTRIBUTORS | 1 + README.md | 1 + 4 files changed, 24 insertions(+) create mode 100644 .github/workflows/ossf.yml diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml new file mode 100644 index 0000000000..a95b846876 --- /dev/null +++ b/.github/workflows/ossf.yml @@ -0,0 +1,21 @@ +name: OSSF Scorecard Weekly + +on: + schedule: + - cron: '0 0 * * 0' # Runs every Sunday at midnight UTC + workflow_dispatch: + +jobs: + ossf-scorecard: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Publish OSSF Scorecard badge to README + uses: ossf/scorecard-action@v2 + with: + publish_results: true + badge: true + branch: main + readme_path: README.md diff --git a/AUTHORS b/AUTHORS index 3e593aaf48..ef905531df 100644 --- a/AUTHORS +++ b/AUTHORS @@ -54,6 +54,7 @@ MongoDB Inc. Nick Hutchinson Norman Heino Oleksandr Sochka +Olga Fadeeva Ori Livneh Paul Redmond Prithvi Rao diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 5c68838bd7..4b015925aa 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -76,6 +76,7 @@ Min-Yih Hsu Nick Hutchinson Norman Heino Oleksandr Sochka +Olga Fadeeva Ori Livneh Pascal Leroy Paul Redmond diff --git a/README.md b/README.md index 4e730256b6..a044cf9e4c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![pylint](https://github.com/google/benchmark/workflows/pylint/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Apylint) [![test-bindings](https://github.com/google/benchmark/workflows/test-bindings/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Atest-bindings) [![Coverage Status](https://coveralls.io/repos/google/benchmark/badge.svg)](https://coveralls.io/r/google/benchmark) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/google/benchmark/badge)](https://securityscorecards.dev/viewer/?uri=github.com/google/benchmark) [![Discord](https://discordapp.com/api/guilds/1125694995928719494/widget.png?style=shield)](https://discord.gg/cz7UX7wKC2) From 12ff2c2583e11135640088d1af0112337e416b64 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 31 Jul 2025 01:40:52 -0700 Subject: [PATCH 365/561] Fix build when targetting Arm64EC using Clang (#2012) --- src/cycleclock.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index 3951ff3546..0671a425f0 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -36,6 +36,9 @@ // declarations of some other intrinsics, breaking compilation. // Therefore, we simply declare __rdtsc ourselves. See also // http://connect.microsoft.com/VisualStudio/feedback/details/262047 +// +// Note that MSVC defines the x64 preprocessor macros when building +// for Arm64EC, despite it using Arm64 assembly instructions. #if defined(COMPILER_MSVC) && !defined(_M_IX86) && !defined(_M_ARM64) && \ !defined(_M_ARM64EC) extern "C" uint64_t __rdtsc(); @@ -79,7 +82,10 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { int64_t ret; __asm__ volatile("rdtsc" : "=A"(ret)); return ret; -#elif defined(__x86_64__) || defined(__amd64__) + +// Note that Clang, like MSVC, defines the x64 preprocessor macros when building +// for Arm64EC, despite it using Arm64 assembly instructions. +#elif (defined(__x86_64__) || defined(__amd64__)) && !defined(__arm64ec__) uint64_t low, high; __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); return static_cast((high << 32) | low); @@ -139,7 +145,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { struct timespec ts = {0, 0}; clock_gettime(CLOCK_MONOTONIC, &ts); return static_cast(ts.tv_sec) * 1000000000 + ts.tv_nsec; -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(__arm64ec__) // System timer of ARMv8 runs at a different frequency than the CPU's. // The frequency is fixed, typically in the range 1-50MHz. It can be // read at CNTFRQ special register. We assume the OS has set up From f402ffd506ff7cc480ff88519a242c6665976778 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 12 Aug 2025 09:05:37 +0100 Subject: [PATCH 366/561] Update README.md removing pylint badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index a044cf9e4c..1d4470e8ed 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![build-and-test](https://github.com/google/benchmark/workflows/build-and-test/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Abuild-and-test) [![bazel](https://github.com/google/benchmark/actions/workflows/bazel.yml/badge.svg)](https://github.com/google/benchmark/actions/workflows/bazel.yml) -[![pylint](https://github.com/google/benchmark/workflows/pylint/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Apylint) [![test-bindings](https://github.com/google/benchmark/workflows/test-bindings/badge.svg)](https://github.com/google/benchmark/actions?query=workflow%3Atest-bindings) [![Coverage Status](https://coveralls.io/repos/google/benchmark/badge.svg)](https://coveralls.io/r/google/benchmark) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/google/benchmark/badge)](https://securityscorecards.dev/viewer/?uri=github.com/google/benchmark) From 6747309e9dbb4d55732d48d8578c00d919f8a87a Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 12 Aug 2025 10:17:01 +0200 Subject: [PATCH 367/561] python: Assert that libdir is a Path in all branches (#1992) The `inplace=True` branch previously relied on some non-trivial interactions between `str` and `pathlib.Path` objects, which produces unexpected values in cases of `s / p`, where `s` is a string and `p` is an absolute path. To fix, just create a `pathlib.Path` of the return value of `build_py.get_package_dir()`. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ed8c396290..d7807b4994 100644 --- a/setup.py +++ b/setup.py @@ -135,7 +135,8 @@ def bazel_build(self, ext: BazelExtension) -> None: # noqa: C901 libdir = Path(self.build_lib) / pkgname else: build_py = self.get_finalized_command("build_py") - libdir = build_py.get_package_dir(pkgname) + libdir = Path(build_py.get_package_dir(pkgname)) + for root, dirs, files in os.walk(srcdir, topdown=True): # exclude runfiles directories and children. dirs[:] = [d for d in dirs if "runfiles" not in d] From 593f861db056b09e9bd683244542536ae33bb62f Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 12 Aug 2025 10:23:26 +0200 Subject: [PATCH 368/561] ci: Update pre-commit hooks and GitHub Action (#2000) * ci: Update pre-commit hooks and GitHub Action Using pre-commit together with uv gives a considerable speedup when running with `--no-sync`, and eliminates the need for our current elaborate caching setup in GitHub Actions. * chore: Switch pre-commit to a PEP735 dependency group And invoke the pre-commit run only with the dev group enabled. This should avoid the costly install on sync. --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 29 +++++------------------------ .pre-commit-config.yaml | 6 +++--- pyproject.toml | 3 ++- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index d56dde93f9..87ab0824ec 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -6,36 +6,17 @@ on: pull_request: branches: [ main ] -env: - CMAKE_GENERATOR: Ninja - jobs: pre-commit: runs-on: ubuntu-latest - env: - MYPY_CACHE_DIR: "${{ github.workspace }}/.cache/mypy" - RUFF_CACHE_DIR: "${{ github.workspace }}/.cache/ruff" - PRE_COMMIT_HOME: "${{ github.workspace }}/.cache/pre-commit" steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: 3.11 - cache: pip - cache-dependency-path: pyproject.toml - - name: Install dependencies - run: python -m pip install ".[dev]" - - name: Cache pre-commit tools - uses: actions/cache@v4 + persist-credentials: false + - name: Install uv + uses: astral-sh/setup-uv@v6 with: - path: | - ${{ env.MYPY_CACHE_DIR }} - ${{ env.RUFF_CACHE_DIR }} - ${{ env.PRE_COMMIT_HOME }} - key: ${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}-linter-cache + python-version: 3.12 - name: Run pre-commit checks - run: pre-commit run --all-files --verbose --show-diff-on-failure + run: uv run --only-group=dev pre-commit run --all-files --verbose --show-diff-on-failure diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 86ceaf623d..00faebadd9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 8.0.3 + rev: 8.2.0 hooks: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.15.0 + rev: v1.16.0 hooks: - id: mypy types_or: [ python, pyi ] @@ -13,6 +13,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.11.13 hooks: - - id: ruff + - id: ruff-check args: [ --fix, --exit-non-zero-on-fix ] - id: ruff-format diff --git a/pyproject.toml b/pyproject.toml index 4595b6dd11..9e56f866e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Testing", "Topic :: System :: Benchmark", ] @@ -27,7 +28,7 @@ dynamic = ["readme", "version"] dependencies = ["absl-py>=0.7.1"] -[project.optional-dependencies] +[dependency-groups] dev = ["pre-commit>=3.3.3"] [project.urls] From 65aeed77f6cc775d34a6ffa928fb0d9c190c9fce Mon Sep 17 00:00:00 2001 From: Arseniy Terekhin Date: Tue, 12 Aug 2025 11:38:24 +0300 Subject: [PATCH 369/561] Python: add bindings for `AddCustomContext` (#1988) * python: add bindings for `AddCustomContext` * fix import order --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- bindings/python/google_benchmark/__init__.py | 1 + bindings/python/google_benchmark/benchmark.cc | 4 ++++ bindings/python/google_benchmark/example.py | 2 ++ 3 files changed, 7 insertions(+) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 44a54f5165..227327131a 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -142,4 +142,5 @@ def main(argv=None): # Methods for use with custom main function. initialize = _benchmark.Initialize run_benchmarks = _benchmark.RunSpecifiedBenchmarks +add_custom_context = _benchmark.AddCustomContext atexit.register(_benchmark.ClearRegisteredBenchmarks) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index 0415b2b68b..dda8851473 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -188,5 +188,9 @@ NB_MODULE(_benchmark, m) { m.def("RunSpecifiedBenchmarks", []() { benchmark::RunSpecifiedBenchmarks(); }); m.def("ClearRegisteredBenchmarks", benchmark::ClearRegisteredBenchmarks); + m.def("AddCustomContext", benchmark::AddCustomContext, nb::arg("key"), + nb::arg("value"), + "Add a key-value pair to output as part of the context stanza in the " + "report."); }; } // namespace diff --git a/bindings/python/google_benchmark/example.py b/bindings/python/google_benchmark/example.py index 5635c41842..8217b409e0 100644 --- a/bindings/python/google_benchmark/example.py +++ b/bindings/python/google_benchmark/example.py @@ -22,6 +22,7 @@ """ import random +import sys import time import google_benchmark as benchmark @@ -137,4 +138,5 @@ def computing_complexity(state): if __name__ == "__main__": + benchmark.add_custom_context("python", sys.version) benchmark.main() From 1a8de56d0e5b8351c166360e01241d16d9a67f4c Mon Sep 17 00:00:00 2001 From: StepSecurity Bot Date: Mon, 11 Aug 2025 22:53:26 -1000 Subject: [PATCH 370/561] [StepSecurity] Apply security best practices (#2018) Signed-off-by: StepSecurity Bot Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/dependabot.yml | 11 ++++++++++ .github/workflows/bazel.yml | 7 +++++-- .../workflows/build-and-test-min-cmake.yml | 4 ++-- .../workflows/build-and-test-perfcounters.yml | 5 ++++- .github/workflows/build-and-test.yml | 12 +++++------ .github/workflows/clang-format-lint.yml | 7 +++++-- .github/workflows/clang-tidy-lint.yml | 5 ++++- .github/workflows/doxygen.yml | 5 ++++- .github/workflows/ossf.yml | 5 ++++- .github/workflows/pre-commit.yml | 4 ++-- .github/workflows/sanitizer.yml | 4 ++-- .github/workflows/test_bindings.yml | 7 +++++-- .github/workflows/wheels.yml | 20 +++++++++---------- 13 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..3661e978bb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + + - package-ecosystem: pip + directory: /tools + schedule: + interval: daily diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index d96687797f..9068ca2660 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -7,6 +7,9 @@ on: env: CMAKE_GENERATOR: Ninja +permissions: + contents: read + jobs: build_and_test_default: name: bazel.${{ matrix.os }} @@ -16,10 +19,10 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: mount bazel cache - uses: actions/cache@v4 + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 env: cache-name: bazel-cache with: diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 2b56e6a63d..46b1ea17bb 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,9 +19,9 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - - uses: lukka/get-cmake@latest + - uses: lukka/get-cmake@f3273e0bcecf2f2c0d3430de21bf02ab2752c47d # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index ad92602d82..0bd3854121 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -9,6 +9,9 @@ on: env: CMAKE_GENERATOR: Ninja +permissions: + contents: read + jobs: job: # TODO(dominic): Extend this to include compiler and set through env: CC/CXX. @@ -20,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4b410d58a3..a6a89237fe 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,10 +30,10 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: build - uses: threeal/cmake-action@v2.1.0 + uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 with: build-dir: ${{ runner.workspace }}/_build cxx-compiler: ${{ matrix.compiler }} @@ -77,9 +77,9 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - - uses: lukka/get-cmake@latest + - uses: lukka/get-cmake@f3273e0bcecf2f2c0d3430de21bf02ab2752c47d # latest - name: configure cmake run: > @@ -117,7 +117,7 @@ jobs: steps: - name: setup msys2 - uses: msys2/setup-msys2@v2 + uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # v2.28.0 with: cache: false msystem: ${{ matrix.msys2.msystem }} @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 3956516752..ec3e43cf1d 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -6,14 +6,17 @@ on: env: CMAKE_GENERATOR: Ninja +permissions: + contents: read + jobs: job: name: check-clang-format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: DoozyX/clang-format-lint-action@v0.18.2 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 with: source: './include/benchmark ./src ./test' clangFormatVersion: 18 diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index b3a8964cbd..bbede66e71 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -7,6 +7,9 @@ on: env: CMAKE_GENERATOR: Ninja +permissions: + contents: read + jobs: job: name: run-clang-tidy @@ -14,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index bcab2c23f3..4e31711412 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -9,13 +9,16 @@ on: env: CMAKE_GENERATOR: Ninja +permissions: + contents: read + jobs: build-and-deploy: name: Build HTML documentation runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index a95b846876..a518a8835e 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -5,12 +5,15 @@ on: - cron: '0 0 * * 0' # Runs every Sunday at midnight UTC workflow_dispatch: +permissions: + contents: read + jobs: ossf-scorecard: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Publish OSSF Scorecard badge to README uses: ossf/scorecard-action@v2 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 87ab0824ec..4a5225a9b8 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,11 +11,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 05c265bbba..f1d9e5f02e 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: configure msan env if: matrix.sanitizer == 'msan' @@ -52,7 +52,7 @@ jobs: echo "ASAN_OPTIONS=alloc_dealloc_mismatch=0" >> $GITHUB_ENV - name: setup clang - uses: egor-tensin/setup-clang@v1 + uses: egor-tensin/setup-clang@ef434b41eb33a70396fb336b1bae39c76d740c3d # v1.4 with: version: latest platform: x64 diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index df02c9f136..6dd63db224 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -9,6 +9,9 @@ on: env: CMAKE_GENERATOR: Ninja +permissions: + contents: read + jobs: python_bindings: name: Test GBM Python ${{ matrix.python-version }} bindings on ${{ matrix.os }} @@ -20,11 +23,11 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} - name: Install GBM Python bindings on ${{ matrix.os }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index a374fa194f..0f219b41d9 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,17 +15,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: fetch-depth: 0 - name: Install Python 3.12 - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.12" - run: python -m pip install build - name: Build sdist run: python -m build --sdist - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: dist-sdist path: dist/*.tar.gz @@ -38,19 +38,19 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-14, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: fetch-depth: 0 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 name: Install Python 3.12 with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@v3.0.0 + uses: pypa/cibuildwheel@5f22145df44122af0f5a201f93cf0207171beca7 # v3.0.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" @@ -64,7 +64,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-13' && 10.14 || 11.0 }} - name: Upload Google Benchmark ${{ matrix.os }} wheels - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: dist-${{ matrix.os }} path: wheelhouse/*.whl @@ -76,9 +76,9 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: dist pattern: dist-* merge-multiple: true - - uses: pypa/gh-action-pypi-publish@release/v1 + - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1 From 1c5dd5f591e9137b179254da9193ac884a9da884 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 12 Aug 2025 13:06:21 +0100 Subject: [PATCH 371/561] Update ossf.yml to use full commit hash v2 isn't even defined for the action, but this is also security hardened. --- .github/workflows/ossf.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index a518a8835e..4060a74d1f 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Publish OSSF Scorecard badge to README - uses: ossf/scorecard-action@v2 + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: publish_results: true badge: true From 8f1b32e94fcbe51ee726ce3e2213a90f1a788ec3 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 12 Aug 2025 13:18:53 +0100 Subject: [PATCH 372/561] trying to get this thing to actually work --- .github/workflows/ossf.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index 4060a74d1f..3d6f38b1ac 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -10,6 +10,10 @@ permissions: jobs: ossf-scorecard: + # To write a badge + permissions: + id-token: write + runs-on: ubuntu-latest steps: - name: Checkout repository @@ -19,6 +23,3 @@ jobs: uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: publish_results: true - badge: true - branch: main - readme_path: README.md From 8b931262e7224520eb8438c92066bf155247a31d Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 12 Aug 2025 13:24:45 +0100 Subject: [PATCH 373/561] copied the latest example --- .github/workflows/ossf.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index 3d6f38b1ac..d6eeb2a18f 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -19,7 +19,9 @@ jobs: - name: Checkout repository uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - - name: Publish OSSF Scorecard badge to README + - name: Run analysis uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: publish_results: true + results_file: ossf_scorecard.json + results_format: json From e629f99927d93aec9ae96d49eb9bd8d7990acd98 Mon Sep 17 00:00:00 2001 From: Arseniy Terekhin Date: Tue, 12 Aug 2025 19:23:37 +0300 Subject: [PATCH 374/561] clang-format python bindings (benchmark.cc) (#2020) --- .github/workflows/clang-format-lint.yml | 2 +- bindings/python/google_benchmark/benchmark.cc | 39 +++++++------------ 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index ec3e43cf1d..c0162e8528 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -18,5 +18,5 @@ jobs: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 with: - source: './include/benchmark ./src ./test' + source: './include/benchmark ./src ./test ./bindings' clangFormatVersion: 18 diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index dda8851473..3b3e937ff2 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -41,7 +41,6 @@ benchmark::internal::Benchmark* RegisterBenchmark(const std::string& name, } NB_MODULE(_benchmark, m) { - using benchmark::TimeUnit; nb::enum_(m, "TimeUnit") .value("kNanosecond", TimeUnit::kNanosecond) @@ -78,47 +77,40 @@ NB_MODULE(_benchmark, m) { .def("args", &Benchmark::Args, nb::rv_policy::reference) .def("range", &Benchmark::Range, nb::rv_policy::reference, nb::arg("start"), nb::arg("limit")) - .def("dense_range", &Benchmark::DenseRange, - nb::rv_policy::reference, nb::arg("start"), - nb::arg("limit"), nb::arg("step") = 1) + .def("dense_range", &Benchmark::DenseRange, nb::rv_policy::reference, + nb::arg("start"), nb::arg("limit"), nb::arg("step") = 1) .def("ranges", &Benchmark::Ranges, nb::rv_policy::reference) - .def("args_product", &Benchmark::ArgsProduct, - nb::rv_policy::reference) + .def("args_product", &Benchmark::ArgsProduct, nb::rv_policy::reference) .def("arg_name", &Benchmark::ArgName, nb::rv_policy::reference) - .def("arg_names", &Benchmark::ArgNames, - nb::rv_policy::reference) - .def("range_pair", &Benchmark::RangePair, - nb::rv_policy::reference, nb::arg("lo1"), nb::arg("hi1"), - nb::arg("lo2"), nb::arg("hi2")) + .def("arg_names", &Benchmark::ArgNames, nb::rv_policy::reference) + .def("range_pair", &Benchmark::RangePair, nb::rv_policy::reference, + nb::arg("lo1"), nb::arg("hi1"), nb::arg("lo2"), nb::arg("hi2")) .def("range_multiplier", &Benchmark::RangeMultiplier, nb::rv_policy::reference) .def("min_time", &Benchmark::MinTime, nb::rv_policy::reference) .def("min_warmup_time", &Benchmark::MinWarmUpTime, nb::rv_policy::reference) - .def("iterations", &Benchmark::Iterations, - nb::rv_policy::reference) - .def("repetitions", &Benchmark::Repetitions, - nb::rv_policy::reference) + .def("iterations", &Benchmark::Iterations, nb::rv_policy::reference) + .def("repetitions", &Benchmark::Repetitions, nb::rv_policy::reference) .def("report_aggregates_only", &Benchmark::ReportAggregatesOnly, nb::rv_policy::reference, nb::arg("value") = true) .def("display_aggregates_only", &Benchmark::DisplayAggregatesOnly, nb::rv_policy::reference, nb::arg("value") = true) .def("measure_process_cpu_time", &Benchmark::MeasureProcessCPUTime, nb::rv_policy::reference) - .def("use_real_time", &Benchmark::UseRealTime, - nb::rv_policy::reference) + .def("use_real_time", &Benchmark::UseRealTime, nb::rv_policy::reference) .def("use_manual_time", &Benchmark::UseManualTime, nb::rv_policy::reference) .def( "complexity", (Benchmark * (Benchmark::*)(benchmark::BigO)) & Benchmark::Complexity, - nb::rv_policy::reference, - nb::arg("complexity") = benchmark::oAuto); + nb::rv_policy::reference, nb::arg("complexity") = benchmark::oAuto); using benchmark::Counter; nb::class_ py_counter(m, "Counter"); - nb::enum_(py_counter, "Flags", nb::is_arithmetic(), nb::is_flag()) + nb::enum_(py_counter, "Flags", nb::is_arithmetic(), + nb::is_flag()) .value("kDefaults", Counter::Flags::kDefaults) .value("kIsRate", Counter::Flags::kIsRate) .value("kAvgThreads", Counter::Flags::kAvgThreads) @@ -161,9 +153,9 @@ NB_MODULE(_benchmark, m) { .def_prop_ro("error_occurred", &State::error_occurred) .def("set_iteration_time", &State::SetIterationTime) .def_prop_rw("bytes_processed", &State::bytes_processed, - &State::SetBytesProcessed) + &State::SetBytesProcessed) .def_prop_rw("complexity_n", &State::complexity_length_n, - &State::SetComplexityN) + &State::SetComplexityN) .def_prop_rw("items_processed", &State::items_processed, &State::SetItemsProcessed) .def("set_label", &State::SetLabel) @@ -183,8 +175,7 @@ NB_MODULE(_benchmark, m) { .def_prop_ro("threads", &State::threads); m.def("Initialize", Initialize); - m.def("RegisterBenchmark", RegisterBenchmark, - nb::rv_policy::reference); + m.def("RegisterBenchmark", RegisterBenchmark, nb::rv_policy::reference); m.def("RunSpecifiedBenchmarks", []() { benchmark::RunSpecifiedBenchmarks(); }); m.def("ClearRegisteredBenchmarks", benchmark::ClearRegisteredBenchmarks); From badec3dd3349d994d118e76a7f2e1eb124ca21ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 19:35:41 +0300 Subject: [PATCH 375/561] Bump actions/checkout from 4.3.0 to 5.0.0 (#2019) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.0 to 5.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/08eba0b27e820071cde6df949e0beb9ba4906955...08c6903cd8c0fde910a37f88322edcfb5dd907a8) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 9068ca2660..af8e4fb5e2 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: mount bazel cache uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 46b1ea17bb..cd5edc4c7b 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,7 +19,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: lukka/get-cmake@f3273e0bcecf2f2c0d3430de21bf02ab2752c47d # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 0bd3854121..0de759b93a 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a6a89237fe..cc638e3016 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,7 +30,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -77,7 +77,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: lukka/get-cmake@f3273e0bcecf2f2c0d3430de21bf02ab2752c47d # latest @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index c0162e8528..cddebc9dac 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index bbede66e71..7a04d67d8a 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 4e31711412..56d315f2fa 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index d6eeb2a18f..0232878a4f 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Run analysis uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 4a5225a9b8..3d8317fa88 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index f1d9e5f02e..61d331e06a 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: configure msan env if: matrix.sanitizer == 'msan' diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 6dd63db224..e51c1f17d9 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 0f219b41d9..68f6931dfd 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 - name: Install Python 3.12 @@ -38,7 +38,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-14, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 From c262996b0ed94bb01454c71d110956344904fb5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 20:58:25 +0300 Subject: [PATCH 376/561] Bump actions/download-artifact from 4.3.0 to 5.0.0 (#2024) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.3.0 to 5.0.0. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/d3f86a106a0bac45b974a628896c90dbdf5c8093...634f93cb2916e3fdff6788551b99b062d0335ce0) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 68f6931dfd..d4148bbe16 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -76,7 +76,7 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: path: dist pattern: dist-* From 7ba35076e37abe1fa4855564dfb5edef677d3e86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 21:11:57 +0300 Subject: [PATCH 377/561] Bump DoozyX/clang-format-lint-action from 0.18.2 to 0.20 (#2025) Bumps [DoozyX/clang-format-lint-action](https://github.com/doozyx/clang-format-lint-action) from 0.18.2 to 0.20. - [Release notes](https://github.com/doozyx/clang-format-lint-action/releases) - [Commits](https://github.com/doozyx/clang-format-lint-action/compare/c71d0bf4e21876ebec3e5647491186f8797fde31...bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73) --- updated-dependencies: - dependency-name: DoozyX/clang-format-lint-action dependency-version: '0.20' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/clang-format-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index cddebc9dac..5e4f4b46fd 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 + - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' clangFormatVersion: 18 From 981e80dc05247bf22cb03545ccadddd58474a5a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 04:07:37 +0300 Subject: [PATCH 378/561] Bump astral-sh/setup-uv from 6.4.3 to 6.5.0 (#2026) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.4.3 to 6.5.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/e92bafb6253dcd438e0484186d7669ea7a8ca1cc...d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 6.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 3d8317fa88..4050d35b71 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3 + uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d4148bbe16..013f122d05 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3 + uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@5f22145df44122af0f5a201f93cf0207171beca7 # v3.0.0 From ba91c42d18b851cd084d51647d06ecf7267bee14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 05:06:34 +0100 Subject: [PATCH 379/561] Bump pypa/cibuildwheel from 3.0.0 to 3.1.3 (#2023) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.0.0 to 3.1.3. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/5f22145df44122af0f5a201f93cf0207171beca7...352e01339f0a173aa2a3eb57f01492e341e83865) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.1.3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 013f122d05..61e55fe653 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@5f22145df44122af0f5a201f93cf0207171beca7 # v3.0.0 + uses: pypa/cibuildwheel@352e01339f0a173aa2a3eb57f01492e341e83865 # v3.1.3 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From 8dd1d8203d07fb8d2ac746fdfb12aff667f143a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 05:13:33 +0100 Subject: [PATCH 380/561] Bump numpy from 1.25 to 2.0.2 in /tools (#2021) Bumps [numpy](https://github.com/numpy/numpy) from 1.25 to 2.0.2. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v1.25.0...v2.0.2) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index f32f35b8fb..41589da2e0 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 1.25 +numpy == 2.0.2 scipy == 1.10.0 From 847dfe43ef6780f1d1c2edf649d76d4093f86221 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 05:32:19 +0100 Subject: [PATCH 381/561] Bump scipy from 1.10.0 to 1.13.1 in /tools (#2022) Bumps [scipy](https://github.com/scipy/scipy) from 1.10.0 to 1.13.1. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.10.0...v1.13.1) --- updated-dependencies: - dependency-name: scipy dependency-version: 1.13.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 41589da2e0..85ba3565f2 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ numpy == 2.0.2 -scipy == 1.10.0 +scipy == 1.13.1 From 1d58aeb1729b2ebab17a3da6018f11286e84512e Mon Sep 17 00:00:00 2001 From: Arseniy Terekhin Date: Wed, 13 Aug 2025 10:41:03 +0300 Subject: [PATCH 382/561] python: fix segfault on empty `argv` in `main()` (#2003) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- bindings/python/google_benchmark/benchmark.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index 3b3e937ff2..175d35160e 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -14,16 +14,18 @@ namespace { namespace nb = nanobind; std::vector Initialize(const std::vector& argv) { - // The `argv` pointers here become invalid when this function returns, but - // benchmark holds the pointer to `argv[0]`. We create a static copy of it - // so it persists, and replace the pointer below. - static std::string executable_name(argv[0]); std::vector ptrs; ptrs.reserve(argv.size()); for (auto& arg : argv) { ptrs.push_back(const_cast(arg.c_str())); } - ptrs[0] = const_cast(executable_name.c_str()); + if (!ptrs.empty()) { + // The `argv` pointers here become invalid when this function returns, but + // benchmark holds the pointer to `argv[0]`. We create a static copy of it + // so it persists, and replace the pointer below. + static std::string executable_name(argv[0]); + ptrs[0] = const_cast(executable_name.c_str()); + } int argc = static_cast(argv.size()); benchmark::Initialize(&argc, ptrs.data()); std::vector remaining_argv; From 7697796fe5a70edbc3394d0593ef82afeebb7ddf Mon Sep 17 00:00:00 2001 From: "Dr. Rita Garcia" Date: Thu, 14 Aug 2025 04:05:05 +1200 Subject: [PATCH 383/561] 2011: Installing contents from benchmark's tools/ subdirectory. (#2016) * 2011: Installing contents from benchmark's tools/ subdirectory. * Incorporating feedback from the PR * Per PR feedback, removing guards to when setting CMAKE_INSTALL_PYTOOLSDIR --- CMakeLists.txt | 1 + src/CMakeLists.txt | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b573ead887..413c56af75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ endif() option(BENCHMARK_ENABLE_INSTALL "Enable installation of benchmark. (Projects embedding benchmark may want to turn this OFF.)" ON) option(BENCHMARK_ENABLE_DOXYGEN "Build documentation with Doxygen." OFF) option(BENCHMARK_INSTALL_DOCS "Enable installation of documentation." ON) +option(BENCHMARK_INSTALL_TOOLS "Enable installation of tools." ON) # Allow unmet dependencies to be met using CMake's ExternalProject mechanics, which # may require downloading the source code. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe7325365f..8e5db4115e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -194,3 +194,11 @@ else() DESTINATION ${CMAKE_INSTALL_DOCDIR}) endif() endif() + +set(CMAKE_INSTALL_PYTOOLSDIR "${CMAKE_INSTALL_DATADIR}/googlebenchmark/tools" CACHE PATH "") + +if (BENCHMARK_ENABLE_INSTALL AND BENCHMARK_INSTALL_TOOLS) + install( + DIRECTORY "${PROJECT_SOURCE_DIR}/tools/" + DESTINATION ${CMAKE_INSTALL_PYTOOLSDIR}) +endif() From 8d19fc0ff202dfbd9ccb22df472ae35f0169c657 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 09:17:16 +0100 Subject: [PATCH 384/561] Bump pypa/cibuildwheel from 3.1.3 to 3.1.4 (#2029) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.1.3 to 3.1.4. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/352e01339f0a173aa2a3eb57f01492e341e83865...c923d83ad9c1bc00211c5041d0c3f73294ff88f6) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.1.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 61e55fe653..e52f81d234 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@352e01339f0a173aa2a3eb57f01492e341e83865 # v3.1.3 + uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From 4b7b129e73361843f8795bffbe93d97b9505116f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:48:40 +0100 Subject: [PATCH 385/561] Bump astral-sh/setup-uv from 6.5.0 to 6.6.0 (#2030) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.5.0 to 6.6.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1...4959332f0f014c5280e7eac8b70c90cb574c9f9b) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 6.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 4050d35b71..cfa7e62b2e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0 + uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e52f81d234..000494e7e1 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0 + uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4 From 9c67fe38770ebbf12a3c2710a2d1901f87ba5f38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:13:41 +0300 Subject: [PATCH 386/561] Bump msys2/setup-msys2 from 2.28.0 to 2.29.0 (#2031) Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.28.0 to 2.29.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/40677d36a502eb2cf0fb808cc9dec31bf6152638...fb197b72ce45fb24f17bf3f807a388985654d1f2) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.29.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index cc638e3016..5c91fc459b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -117,7 +117,7 @@ jobs: steps: - name: setup msys2 - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # v2.28.0 + uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 with: cache: false msystem: ${{ matrix.msys2.msystem }} From ed234a3f6f8f2c8ccae69738be4fda96f829915b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 11:53:58 +0100 Subject: [PATCH 387/561] Bump astral-sh/setup-uv from 6.6.0 to 6.6.1 (#2032) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.6.0 to 6.6.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/4959332f0f014c5280e7eac8b70c90cb574c9f9b...557e51de59eb14aaaba2ed9621916900a91d50c6) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 6.6.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index cfa7e62b2e..73540c345a 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0 + uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 000494e7e1..51b00cbc24 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0 + uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4 From fde61addd449a15a19ce08ab0f7d95e0478017df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 12:06:26 +0100 Subject: [PATCH 388/561] Bump lukka/get-cmake from 4.1.0 to 4.1.1 (#2033) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/f3273e0bcecf2f2c0d3430de21bf02ab2752c47d...2ecc21724e5215b0e567bc399a2602d2ecb48541) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.1.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index cd5edc4c7b..c00b1cfcc2 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: lukka/get-cmake@f3273e0bcecf2f2c0d3430de21bf02ab2752c47d # latest + - uses: lukka/get-cmake@2ecc21724e5215b0e567bc399a2602d2ecb48541 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5c91fc459b..4fdd131d8c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: lukka/get-cmake@f3273e0bcecf2f2c0d3430de21bf02ab2752c47d # latest + - uses: lukka/get-cmake@2ecc21724e5215b0e567bc399a2602d2ecb48541 # latest - name: configure cmake run: > From 3a8ce453b4ac9486f8b7a020d7558189f7101044 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:05:06 +0100 Subject: [PATCH 389/561] Bump actions/setup-python from 5.6.0 to 6.0.0 (#2035) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.6.0 to 6.0.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/a26af69be951a213d495a4c3e4e4022e16d87065...e797f83bcb11b83ae66e0230d6156d7c80228e7c) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index e51c1f17d9..1aab02f6e9 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -27,7 +27,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: ${{ matrix.python-version }} - name: Install GBM Python bindings on ${{ matrix.os }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 51b00cbc24..f4ecafca3b 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -19,7 +19,7 @@ jobs: with: fetch-depth: 0 - name: Install Python 3.12 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: "3.12" - run: python -m pip install build @@ -42,7 +42,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 name: Install Python 3.12 with: python-version: "3.12" From 161441541184b185e7f77e5d78110bf4d89e86e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:10:40 +0100 Subject: [PATCH 390/561] Bump pypa/gh-action-pypi-publish from 1.12.4 to 1.13.0 (#2034) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.12.4 to 1.13.0. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/76f52bc884231f62b9a034ebfe128415bbaabdfc...ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-version: 1.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f4ecafca3b..c7b052df7e 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -81,4 +81,4 @@ jobs: path: dist pattern: dist-* merge-multiple: true - - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1 + - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 From 5f7d66929fb66869d96dfcbacf0d8a586b33766d Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 11 Sep 2025 18:24:44 -0700 Subject: [PATCH 391/561] Add initializer for statistics field (#2038) Copying uninitialized pointers is undefined behavior, and security mitigations such as structure protection [1] take advantage of this. Previously benchmarks would crash when copying the uninitialized statistics field; fix the crash by initializing it. [1] https://discourse.llvm.org/t/rfc-structure-protection-a-family-of-uaf-mitigation-techniques/85555 --- include/benchmark/benchmark.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index f88f648e79..3d83a4d2e5 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1821,6 +1821,7 @@ class BENCHMARK_EXPORT BenchmarkReporter { complexity(oNone), complexity_lambda(), complexity_n(0), + statistics(), report_big_o(false), report_rms(false), allocs_per_iter(0.0) {} From b2959a733d26ca5f0c2a765069d8ae37f7b03fd8 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 15 Sep 2025 11:53:26 +0300 Subject: [PATCH 392/561] JSON reporter: make int dumping always happen in C locale (#2040) The test fails without the fix. Fixes https://github.com/google/benchmark/issues/2039 --- src/json_reporter.cc | 4 ++- test/CMakeLists.txt | 3 ++ test/locale_impermeability_test.cc | 47 ++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 test/locale_impermeability_test.cc diff --git a/src/json_reporter.cc b/src/json_reporter.cc index deff77e9ac..2b84cd14a5 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -81,7 +81,9 @@ std::string FormatKV(std::string const& key, bool value) { std::string FormatKV(std::string const& key, int64_t value) { std::stringstream ss; - ss << '"' << StrEscape(key) << "\": " << value; + // We really want to just dump the integer as-is, + // without the system locale interfering. + ss << '"' << StrEscape(key) << "\": " << std::to_string(value); return ss.str(); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b7a6ac4899..8c04ec3885 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -219,6 +219,9 @@ benchmark_add_test(NAME profiler_manager_iterations COMMAND profiler_manager_ite compile_output_test(complexity_test) benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=1000000x) +compile_output_test(locale_impermeability_test) +benchmark_add_test(NAME locale_impermeability_test COMMAND locale_impermeability_test) + ############################################################################### # GoogleTest Unit Tests ############################################################################### diff --git a/test/locale_impermeability_test.cc b/test/locale_impermeability_test.cc new file mode 100644 index 0000000000..b98eb53930 --- /dev/null +++ b/test/locale_impermeability_test.cc @@ -0,0 +1,47 @@ +#undef NDEBUG +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +static void BM_ostream(benchmark::State &state) { +#if !defined(__MINGW64__) || defined(__clang__) + // GCC-based versions of MINGW64 do not support locale manipulations, + // don't run the test under them. + std::locale::global(std::locale("en_US.UTF-8")); +#endif + while (state.KeepRunning()) { + state.SetIterationTime(1e-6); + } +} +BENCHMARK(BM_ostream)->UseManualTime()->Iterations(1000000); + +ADD_CASES(TC_ConsoleOut, {{"^BM_ostream/iterations:1000000/manual_time" + " %console_report$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_ostream/iterations:1000000/manual_time\",$"}, + {"\"family_index\": 0,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": " + "\"BM_ostream/iterations:1000000/manual_time\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": 1000000,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\"$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_ostream/iterations:1000000/" + "manual_time\",1000000,%float,%float,ns,,,,,$"}}); + +int main(int argc, char *argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} From d65c35c406858939084ef96c72663ec382f75d37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 09:55:05 +0100 Subject: [PATCH 393/561] Bump astral-sh/setup-uv from 6.6.1 to 6.7.0 (#2041) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.6.1 to 6.7.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/557e51de59eb14aaaba2ed9621916900a91d50c6...b75a909f75acd358c2196fb9a5f1299a9a8868a4) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 6.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 73540c345a..78e64e570c 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 + uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c7b052df7e..efd37fe2ef 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1 + uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4 From 2948b6a2e61ccabecc952c24794c6960d86c9ed6 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:14:09 +0100 Subject: [PATCH 394/561] Adding explicit cast to aid in template argument deduction. (#2042) * Adding explicit cast to aid in template argument deduction. The `BENCHMARK(my_func)` macro needs to register the function my_func so the library can run it. It uses `std::make_unique` to create an object that stores metadata about the benchmark, including its name ("my_func") and a pointer to the function itself (my_func). The specific constructor being called via `std::make_unique` is for `benchmark::internal::FunctionBenchmark`. When a benchmark function name is overloaded, the compiler can't determine which function is being referred to until the call is made with specific arguments, or enough context is provided. The addition of a `static_cast` to the expected `Function*` type resolves any ambiguity as the compiler is forced to pick the one with the matching signature. * clang-format * add a test * clang-format again --- include/benchmark/benchmark.h | 33 +++++++++++++++++++-------------- test/overload_gtest.cc | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 14 deletions(-) create mode 100644 test/overload_gtest.cc diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 3d83a4d2e5..8144518bd7 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1503,12 +1503,13 @@ class Fixture : public internal::Benchmark { static ::benchmark::internal::Benchmark const* const BENCHMARK_PRIVATE_NAME( \ n) BENCHMARK_UNUSED -#define BENCHMARK(...) \ - BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>(#__VA_ARGS__, \ - __VA_ARGS__))) +#define BENCHMARK(...) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #__VA_ARGS__, \ + static_cast<::benchmark::internal::Function*>(__VA_ARGS__)))) // Old-style macros #define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) @@ -1549,21 +1550,25 @@ class Fixture : public internal::Benchmark { BENCHMARK_PRIVATE_DECLARE(n) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>(#n "<" #a ">", n))) + ::benchmark::internal::FunctionBenchmark>( \ + #n "<" #a ">", \ + static_cast<::benchmark::internal::Function*>(n)))) -#define BENCHMARK_TEMPLATE2(n, a, b) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>(#n "<" #a "," #b ">", \ - n))) +#define BENCHMARK_TEMPLATE2(n, a, b) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #n "<" #a "," #b ">", \ + static_cast<::benchmark::internal::Function*>(n)))) #define BENCHMARK_TEMPLATE(n, ...) \ BENCHMARK_PRIVATE_DECLARE(n) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>( \ - #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) + #n "<" #__VA_ARGS__ ">", \ + static_cast<::benchmark::internal::Function*>(n<__VA_ARGS__>)))) // This will register a benchmark for a templatized function, // with the additional arguments specified by `...`. diff --git a/test/overload_gtest.cc b/test/overload_gtest.cc new file mode 100644 index 0000000000..5ca11a9dc6 --- /dev/null +++ b/test/overload_gtest.cc @@ -0,0 +1,33 @@ +#include "benchmark/benchmark.h" + +// Simulate an overloaded function name. +// This version does nothing and is just here to create ambiguity for +// MyOverloadedBenchmark. +void MyOverloadedBenchmark() {} + +// This is the actual benchmark function we want to register. +// It has the signature void(benchmark::State&) required by the library. +void MyOverloadedBenchmark(benchmark::State& state) { + for (auto _ : state) { + } +} + +// This macro invocation should compile correctly if benchmark.h +// contains the fix (using static_cast), but would fail to compile +// if the benchmark name were ambiguous (e.g., when using + or no cast +// with an overloaded function). +BENCHMARK(MyOverloadedBenchmark); + +// Also test BENCHMARK_TEMPLATE with an overloaded name. +template +void MyTemplatedOverloadedBenchmark() {} + +template +void MyTemplatedOverloadedBenchmark(benchmark::State& state) { + for (auto _ : state) { + } +} + +BENCHMARK_TEMPLATE(MyTemplatedOverloadedBenchmark, 1); + +BENCHMARK_MAIN(); From bc6e22310ab99df4211ef834323e6bbd681f85b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:44:34 +0100 Subject: [PATCH 395/561] Bump pypa/cibuildwheel from 3.1.4 to 3.2.0 (#2043) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.1.4 to 3.2.0. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/c923d83ad9c1bc00211c5041d0c3f73294ff88f6...7c619efba910c04005a835b110b057fc28fd6e93) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index efd37fe2ef..761adc00f5 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@c923d83ad9c1bc00211c5041d0c3f73294ff88f6 # v3.1.4 + uses: pypa/cibuildwheel@7c619efba910c04005a835b110b057fc28fd6e93 # v3.2.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From 01deef52a407ef416b69dcead8fca1f0c3aa5aed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:44:46 +0100 Subject: [PATCH 396/561] Bump actions/cache from 4.2.4 to 4.3.0 (#2044) Bumps [actions/cache](https://github.com/actions/cache) from 4.2.4 to 4.3.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/0400d5f644dc74513175e3cd8d07132dd4860809...0057852bfaa89a56745cba8c7296529d2fc39830) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index af8e4fb5e2..ce8de66082 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: mount bazel cache - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 env: cache-name: bazel-cache with: From 8afba0b13a8b7221f6677b764159240438cd02e6 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Mon, 29 Sep 2025 16:50:44 +0100 Subject: [PATCH 397/561] remove done todo --- src/string_util.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/string_util.cc b/src/string_util.cc index 420de4cf25..1ba39dd088 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -117,8 +117,8 @@ std::string StrFormatImp(const char* msg, va_list args) { va_list args_cp; va_copy(args_cp, args); - // TODO(ericwf): use std::array for first attempt to avoid one memory - // allocation guess what the size might be + // Use std::array for first attempt to avoid one memory allocation guess what + // the size might be std::array local_buff = {}; // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation From fa782d53dca50666cdcbcffd319a2f8026baa669 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:56:02 +0100 Subject: [PATCH 398/561] Bump astral-sh/setup-uv from 6.7.0 to 6.8.0 (#2045) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.7.0 to 6.8.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/b75a909f75acd358c2196fb9a5f1299a9a8868a4...d0cc045d04ccac9d8b7881df0226f9e82c39688e) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 6.8.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 78e64e570c..69ea77b4b0 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0 + uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 761adc00f5..7107485756 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0 + uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@7c619efba910c04005a835b110b057fc28fd6e93 # v3.2.0 From 7ad8b80aee5bb067b0d3e01de6ba22a44053f89d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 10:54:59 +0100 Subject: [PATCH 399/561] Bump ossf/scorecard-action from 2.4.2 to 2.4.3 (#2047) Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.2 to 2.4.3. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/05b42c624433fc40578a4040d5cf5e36ddca8cde...4eaacf0543bb3f2c246792bd56e8cdeffafb205a) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-version: 2.4.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ossf.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index 0232878a4f..496f348cea 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Run analysis - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: publish_results: true results_file: ossf_scorecard.json From 40b63f08f7d2d6d8695f2e0b0ddcac85d413aa89 Mon Sep 17 00:00:00 2001 From: Chase Naples Date: Thu, 2 Oct 2025 06:10:20 -0400 Subject: [PATCH 400/561] Guard feature checks against failed compilation (#2046) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- cmake/CXXFeatureCheck.cmake | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index 0dfe93dc0d..ee5b7591e2 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -64,19 +64,19 @@ function(cxx_feature_check FILE) endif() endif() - if(RUN_${FEATURE} EQUAL 0) - message(STATUS "Performing Test ${FEATURE} -- success") - set(HAVE_${VAR} 1 PARENT_SCOPE) - add_definitions(-DHAVE_${VAR}) - else() - if(NOT COMPILE_${FEATURE}) - if(CXXFEATURECHECK_DEBUG) - message(STATUS "Performing Test ${FEATURE} -- failed to compile: ${COMPILE_OUTPUT_VAR}") - else() - message(STATUS "Performing Test ${FEATURE} -- failed to compile") - endif() + if(COMPILE_${FEATURE}) + if(DEFINED RUN_${FEATURE} AND RUN_${FEATURE} EQUAL 0) + message(STATUS "Performing Test ${FEATURE} -- success") + set(HAVE_${VAR} 1 PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) else() message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run") endif() + else() + if(CXXFEATURECHECK_DEBUG) + message(STATUS "Performing Test ${FEATURE} -- failed to compile: ${COMPILE_OUTPUT_VAR}") + else() + message(STATUS "Performing Test ${FEATURE} -- failed to compile") + endif() endif() endfunction() From ef2da7b245c7a862d3fca23cdd903c7e6dd7f8d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 10:57:48 +0100 Subject: [PATCH 401/561] Bump lukka/get-cmake from 4.1.1 to 4.1.2 (#2048) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.1.1 to 4.1.2. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/2ecc21724e5215b0e567bc399a2602d2ecb48541...628dd514bed37cb0a609e84a6186cbbaa2fc0140) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index c00b1cfcc2..f37b814f0b 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: lukka/get-cmake@2ecc21724e5215b0e567bc399a2602d2ecb48541 # latest + - uses: lukka/get-cmake@628dd514bed37cb0a609e84a6186cbbaa2fc0140 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4fdd131d8c..5a368c04d2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: lukka/get-cmake@2ecc21724e5215b0e567bc399a2602d2ecb48541 # latest + - uses: lukka/get-cmake@628dd514bed37cb0a609e84a6186cbbaa2fc0140 # latest - name: configure cmake run: > From bfe96c4287637f03e8ae45fb997bb5c25cd9bb1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 09:49:02 +0100 Subject: [PATCH 402/561] Bump numpy from 2.0.2 to 2.3.3 in /tools (#2049) Bumps [numpy](https://github.com/numpy/numpy) from 2.0.2 to 2.3.3. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.0.2...v2.3.3) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.3.3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 85ba3565f2..126ff2b477 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.0.2 +numpy == 2.3.3 scipy == 1.13.1 From be59db518e8e8a7c4dffcedcba9c76ea45507fec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:54:15 +0100 Subject: [PATCH 403/561] Bump scipy from 1.13.1 to 1.16.2 in /tools (#2050) Bumps [scipy](https://github.com/scipy/scipy) from 1.13.1 to 1.16.2. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.13.1...v1.16.2) --- updated-dependencies: - dependency-name: scipy dependency-version: 1.16.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 126ff2b477..fb539d7959 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ numpy == 2.3.3 -scipy == 1.13.1 +scipy == 1.16.2 From 4e26a9e6eedb3e89c448cf7115352cb085fdb713 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:20:05 +0100 Subject: [PATCH 404/561] Bump astral-sh/setup-uv from 6.8.0 to 7.0.0 (#2051) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.8.0 to 7.0.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/d0cc045d04ccac9d8b7881df0226f9e82c39688e...eb1897b8dc4b5d5bfe39a428a8f2304605e0983c) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 69ea77b4b0..657184b123 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 + uses: astral-sh/setup-uv@eb1897b8dc4b5d5bfe39a428a8f2304605e0983c # v7.0.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 7107485756..e74fcf69cd 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 + uses: astral-sh/setup-uv@eb1897b8dc4b5d5bfe39a428a8f2304605e0983c # v7.0.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@7c619efba910c04005a835b110b057fc28fd6e93 # v3.2.0 From 3c5cbdefecd2e74eb037a91b859a3c99649570e0 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 13 Oct 2025 17:12:59 +0200 Subject: [PATCH 405/561] dev: Update pre-commit hooks and `nanobind_bazel` version (#2053) * dev: Update `nanobind_bazel` and pre-commit hooks Also add `uv.lock` to the list of ignored Python build artifacts. * Fix mypy unused-variable warnings An underscore is the preferred option for ignoring an unused variable obtained from a structured binding (i.e., tuple unpacking) in Python. --- .gitignore | 1 + .pre-commit-config.yaml | 6 +++--- MODULE.bazel | 2 +- tools/compare.py | 4 ++-- tools/strip_asm.py | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 24a1fb6d74..8f6ce84efe 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ CMakeSettings.json # Python build stuff dist/ *.egg-info* +uv.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 00faebadd9..57af012f7a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,17 @@ repos: - repo: https://github.com/keith/pre-commit-buildifier - rev: 8.2.0 + rev: 8.2.1 hooks: - id: buildifier - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.16.0 + rev: v1.18.2 hooks: - id: mypy types_or: [ python, pyi ] args: [ "--ignore-missing-imports", "--scripts-are-modules" ] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.13 + rev: v0.14.0 hooks: - id: ruff-check args: [ --fix, --exit-non-zero-on-fix ] diff --git a/MODULE.bazel b/MODULE.bazel index 7390c98ad3..620e3d030f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -38,4 +38,4 @@ use_repo(pip, "tools_pip_deps") # -- bazel_dep definitions -- # -bazel_dep(name = "nanobind_bazel", version = "2.7.0", dev_dependency = True) +bazel_dep(name = "nanobind_bazel", version = "2.9.2", dev_dependency = True) diff --git a/tools/compare.py b/tools/compare.py index 1dd9de239f..1a656345c2 100755 --- a/tools/compare.py +++ b/tools/compare.py @@ -21,8 +21,8 @@ def check_inputs(in1, in2, flags): """ Perform checking on the user provided inputs and diagnose any abnormalities """ - in1_kind, in1_err = util.classify_input_file(in1) - in2_kind, in2_err = util.classify_input_file(in2) + in1_kind, _ = util.classify_input_file(in1) + in2_kind, _ = util.classify_input_file(in2) output_file = util.find_benchmark_flag("--benchmark_out=", flags) output_type = util.find_benchmark_flag("--benchmark_out_format=", flags) if ( diff --git a/tools/strip_asm.py b/tools/strip_asm.py index 14d80ed48d..f49a8c85ac 100755 --- a/tools/strip_asm.py +++ b/tools/strip_asm.py @@ -141,7 +141,7 @@ def main(): parser.add_argument( "out", metavar="output", type=str, nargs=1, help="The output file" ) - args, unknown_args = parser.parse_known_args() + args, _ = parser.parse_known_args() input = args.input[0] output = args.out[0] if not os.path.isfile(input): From b7965973c6f3bcc05d1c857d73db9cb5e963d162 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 13 Oct 2025 19:11:08 +0200 Subject: [PATCH 406/561] wheels: Update GitHub Actions runner to avoid errors due to macOS x86_64 deprecation (#2054) GitHub has deprecated the `macos-13` runner image, and recommends using the `macos-15-intel` or `macos-14-large` images for macOS x86 builds. Hence, for the x86 wheel build job, change `runner.os` to be `macos-15-intel`. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e74fcf69cd..ea0a065334 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -35,7 +35,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-14, windows-latest] + os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -61,7 +61,7 @@ jobs: CIBW_ENVIRONMENT_LINUX: PATH=$PATH:$HOME/bin CIBW_TEST_COMMAND: python {project}/bindings/python/google_benchmark/example.py # unused by Bazel, but needed explicitly by delocate on MacOS. - MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-13' && 10.14 || 11.0 }} + MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-15-intel' && 10.14 || 11.0 }} - name: Upload Google Benchmark ${{ matrix.os }} wheels uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 From 37522dc7f338aefa460c1e6584a5749b19abbccd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 10:45:03 +0100 Subject: [PATCH 407/561] Bump pypa/cibuildwheel from 3.2.0 to 3.2.1 (#2056) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.2.0 to 3.2.1. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/7c619efba910c04005a835b110b057fc28fd6e93...9c00cb4f6b517705a3794b22395aedc36257242c) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index ea0a065334..70ff7e6ed1 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@eb1897b8dc4b5d5bfe39a428a8f2304605e0983c # v7.0.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@7c619efba910c04005a835b110b057fc28fd6e93 # v3.2.0 + uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From c2917683a1e456ba9831dd59b728cecc95257567 Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Tue, 14 Oct 2025 12:05:06 +0200 Subject: [PATCH 408/561] bindings(python): Remove hard `absl-py` dependency (#2052) * bindings(python): Remove hard `absl-py` dependency This commit refactors the public `google_benchmark` APIs to work without `absl-py` installed in the current virtual environment. It also removes `absl-py` from the list of PyPI package dependencies. To restore the previous behavior, users can implement a custom `main()` function using `absl.app` as command-line parser + runner, for example as the previous default `main()` function that is removed by this very commit. * bindings(python): Remove private methods They are no longer useful without absl. Instead, users can call the exposed C++ bindings (`_benchmark.Initialize()` and `_benchmark.RunSpecifiedBenchmarks`) directly, all within a custom `main()` function. --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- bindings/python/google_benchmark/__init__.py | 16 +++------------- pyproject.toml | 2 -- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 227327131a..040bdff0c7 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -29,8 +29,6 @@ def my_benchmark(state): import atexit -from absl import app - from google_benchmark import _benchmark from google_benchmark._benchmark import ( Counter as Counter, @@ -122,21 +120,13 @@ def register(undefined=None, *, name=None): return options.func -def _flags_parser(argv): - argv = _benchmark.Initialize(argv) - return app.parse_flags_with_usage(argv) - +def main(argv: list[str] | None = None) -> None: + import sys -def _run_benchmarks(argv): - if len(argv) > 1: - raise app.UsageError("Too many command-line arguments.") + _benchmark.Initialize(argv or sys.argv) return _benchmark.RunSpecifiedBenchmarks() -def main(argv=None): - return app.run(_run_benchmarks, argv=argv, flags_parser=_flags_parser) - - # FIXME: can we rerun with disabled ASLR? # Methods for use with custom main function. diff --git a/pyproject.toml b/pyproject.toml index 9e56f866e4..f55daf2606 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,8 +26,6 @@ classifiers = [ dynamic = ["readme", "version"] -dependencies = ["absl-py>=0.7.1"] - [dependency-groups] dev = ["pre-commit>=3.3.3"] From 6d1aced6dc88555ee3939c21e3d8de2a8a73ec3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 11:21:35 +0100 Subject: [PATCH 409/561] Bump astral-sh/setup-uv from 7.0.0 to 7.1.0 (#2055) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.0.0 to 7.1.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/eb1897b8dc4b5d5bfe39a428a8f2304605e0983c...3259c6206f993105e3a61b142c2d97bf4b9ef83d) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 657184b123..e0f0675b44 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@eb1897b8dc4b5d5bfe39a428a8f2304605e0983c # v7.0.0 + uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 70ff7e6ed1..7716e85f89 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@eb1897b8dc4b5d5bfe39a428a8f2304605e0983c # v7.0.0 + uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 From 4165bf232b68e854f688e2d275652be14a3d0600 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 10:17:27 +0100 Subject: [PATCH 410/561] Bump numpy from 2.3.3 to 2.3.4 in /tools (#2058) Bumps [numpy](https://github.com/numpy/numpy) from 2.3.3 to 2.3.4. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.3.3...v2.3.4) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.3.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index fb539d7959..9999698040 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.3.3 +numpy == 2.3.4 scipy == 1.16.2 From d029e781f6f32146e92988ec81c2180b99094172 Mon Sep 17 00:00:00 2001 From: Cole Sturza <43652373+colesturza@users.noreply.github.com> Date: Thu, 16 Oct 2025 04:16:38 -0600 Subject: [PATCH 411/561] fix: add missing override key word to ThreadRunnerDefault::RunThreads in benchmark_runner.cc (#2060) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- src/benchmark_runner.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 1f5bb6b79f..0e7d4a792c 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -191,7 +191,7 @@ class ThreadRunnerDefault : public ThreadRunnerBase { explicit ThreadRunnerDefault(int num_threads) : pool(static_cast(num_threads - 1)) {} - void RunThreads(const std::function& fn) final { + void RunThreads(const std::function& fn) override final { // Run all but one thread in separate threads for (std::size_t ti = 0; ti < pool.size(); ++ti) { pool[ti] = std::thread(fn, static_cast(ti + 1)); From 7b9e482e3dbbfaa96c0d334a30ab8c22b69ee868 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:51:29 +0100 Subject: [PATCH 412/561] Bump astral-sh/setup-uv from 7.1.0 to 7.1.1 (#2061) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.0 to 7.1.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/3259c6206f993105e3a61b142c2d97bf4b9ef83d...2ddd2b9cb38ad8efd50337e8ab201519a34c9f24) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index e0f0675b44..0ee9f893d7 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0 + uses: astral-sh/setup-uv@2ddd2b9cb38ad8efd50337e8ab201519a34c9f24 # v7.1.1 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 7716e85f89..3a092565d5 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0 + uses: astral-sh/setup-uv@2ddd2b9cb38ad8efd50337e8ab201519a34c9f24 # v7.1.1 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 From 8498a2a03946c311ee448289676e7006d89eed16 Mon Sep 17 00:00:00 2001 From: wieDasDing <6884440+dingxiangfei2009@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:58:38 +0200 Subject: [PATCH 413/561] Fix warnings from Clang (#2062) * Fix warnings from Clang This patch addresses a few issues: - Wformat-nonliteral from colour printing functions - Wmissing-prototypes from a few internal functions Signed-off-by: Xiangfei Ding * Wrap tests in anonymous namespaces Technically tests should be using internal linkage. Signed-off-by: Xiangfei Ding --------- Signed-off-by: Xiangfei Ding --- src/benchmark.cc | 3 ++ src/colorprint.h | 15 +++++++++- src/commandlineflags.cc | 4 +++ src/complexity.cc | 9 +++++- src/counter.cc | 4 +++ src/csv_reporter.cc | 9 ++---- test/basic_test.cc | 2 ++ test/benchmark_min_time_flag_iters_test.cc | 7 ++--- test/benchmark_min_time_flag_time_test.cc | 6 ++-- test/benchmark_setup_teardown_test.cc | 18 +++++------- test/benchmark_test.cc | 34 ++++++++++------------ test/complexity_test.cc | 24 +++++++-------- test/diagnostics_test.cc | 2 ++ test/display_aggregates_only_test.cc | 2 ++ test/donotoptimize_assembly_test.cc | 7 +++-- test/filter_test.cc | 13 ++++----- test/internal_threading_test.cc | 6 ++-- test/link_main_test.cc | 2 ++ test/locale_impermeability_test.cc | 8 ++--- test/map_test.cc | 5 ++-- test/memory_manager_test.cc | 3 +- test/multiple_ranges_test.cc | 4 ++- test/options_test.cc | 2 ++ test/output_test_helper.cc | 14 +++++---- test/overload_gtest.cc | 4 ++- test/perf_counters_test.cc | 8 +++-- test/profiler_manager_iterations_test.cc | 5 ++-- test/profiler_manager_test.cc | 2 ++ test/register_benchmark_test.cc | 3 +- test/repetitions_test.cc | 6 ++-- test/report_aggregates_only_test.cc | 2 ++ test/reporter_output_test.cc | 7 ++--- test/skip_with_error_test.cc | 21 +++++++------ test/spec_arg_test.cc | 8 ++--- test/spec_arg_verbosity_test.cc | 4 ++- test/state_assembly_test.cc | 1 + test/user_counters_tabular_test.cc | 2 ++ test/user_counters_test.cc | 26 +++++++++++++++-- test/user_counters_thousands_test.cc | 2 ++ 39 files changed, 185 insertions(+), 119 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 02161f90bb..fc36fedb19 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -723,6 +723,7 @@ namespace internal { void (*HelperPrintf)(); +namespace { void PrintUsageAndExit() { HelperPrintf(); std::flush(std::cout); @@ -811,6 +812,8 @@ void ParseCommandLineFlags(int* argc, char** argv) { } } +} // end namespace + int InitializeStreams() { static std::ios_base::Init init; return 0; diff --git a/src/colorprint.h b/src/colorprint.h index 9f6fab9b34..477a030fd2 100644 --- a/src/colorprint.h +++ b/src/colorprint.h @@ -17,11 +17,24 @@ enum LogColor { COLOR_WHITE }; +#if defined(__GNUC__) || defined(__clang__) +#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \ + __attribute__((format(printf, format_arg, first_idx))) +#elif defined(__MINGW32__) +#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \ + __attribute__((format(__MINGW_PRINTF_FORMAT, format_arg, first_idx))) +#else +#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) +#endif + +PRINTF_FORMAT_STRING_FUNC(1, 0) std::string FormatString(const char* msg, va_list args); -std::string FormatString(const char* msg, ...); +PRINTF_FORMAT_STRING_FUNC(1, 2) std::string FormatString(const char* msg, ...); +PRINTF_FORMAT_STRING_FUNC(3, 0) void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, va_list args); +PRINTF_FORMAT_STRING_FUNC(3, 4) void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...); // Returns true if stdout appears to be a terminal that supports colored diff --git a/src/commandlineflags.cc b/src/commandlineflags.cc index 3ab280a028..99a240c122 100644 --- a/src/commandlineflags.cc +++ b/src/commandlineflags.cc @@ -179,6 +179,8 @@ std::map KvPairsFromEnv( return value; } +namespace { + // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. @@ -217,6 +219,8 @@ const char* ParseFlagValue(const char* str, const char* flag, return flag_end + 1; } +} // end namespace + BENCHMARK_EXPORT bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. diff --git a/src/complexity.cc b/src/complexity.cc index a474645a0d..4c9ef6d0c7 100644 --- a/src/complexity.cc +++ b/src/complexity.cc @@ -17,7 +17,6 @@ #include "complexity.h" -#include #include #include "benchmark/benchmark.h" @@ -25,6 +24,8 @@ namespace benchmark { +namespace { + // Internal function to calculate the different scalability forms BigOFunc* FittingCurve(BigO complexity) { switch (complexity) { @@ -48,6 +49,8 @@ BigOFunc* FittingCurve(BigO complexity) { } } +} // end namespace + // Function to return an string for the calculated complexity std::string GetBigOString(BigO complexity) { switch (complexity) { @@ -68,6 +71,8 @@ std::string GetBigOString(BigO complexity) { } } +namespace { + // Find the coefficient for the high-order term in the running time, by // minimizing the sum of squares of relative error, for the fitting curve // given by the lambda expression. @@ -152,6 +157,8 @@ LeastSq MinimalLeastSq(const std::vector& n, return best_fit; } +} // end namespace + std::vector ComputeBigO( const std::vector& reports) { typedef BenchmarkReporter::Run Run; diff --git a/src/counter.cc b/src/counter.cc index a76bf76770..4bdd5e9b59 100644 --- a/src/counter.cc +++ b/src/counter.cc @@ -17,6 +17,8 @@ namespace benchmark { namespace internal { +namespace { + double Finish(Counter const& c, IterationCount iterations, double cpu_time, double num_threads) { double v = c.value; @@ -39,6 +41,8 @@ double Finish(Counter const& c, IterationCount iterations, double cpu_time, return v; } +} // namespace + void Finish(UserCounters* l, IterationCount iterations, double cpu_time, double num_threads) { for (auto& c : *l) { diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 3ee434b43c..0f998045bd 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -12,29 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include #include #include -#include #include #include "benchmark/benchmark.h" #include "check.h" #include "complexity.h" -#include "string_util.h" -#include "timers.h" // File format reference: http://edoceo.com/utilitas/csv-file-format. namespace benchmark { namespace { -std::vector elements = { +const std::vector elements = { "name", "iterations", "real_time", "cpu_time", "time_unit", "bytes_per_second", "items_per_second", "label", "error_occurred", "error_message"}; -} // namespace std::string CsvEscape(const std::string& s) { std::string tmp; @@ -51,6 +45,7 @@ std::string CsvEscape(const std::string& s) { } return '"' + tmp + '"'; } +} // namespace BENCHMARK_EXPORT bool CSVReporter::ReportContext(const Context& context) { diff --git a/test/basic_test.cc b/test/basic_test.cc index b51494bdc4..068cd98476 100644 --- a/test/basic_test.cc +++ b/test/basic_test.cc @@ -3,6 +3,7 @@ #define BASIC_BENCHMARK_TEST(x) BENCHMARK(x)->Arg(8)->Arg(512)->Arg(8192) +namespace { void BM_empty(benchmark::State& state) { for (auto _ : state) { auto iterations = static_cast(state.iterations()) * @@ -174,5 +175,6 @@ static_assert( benchmark::State::StateIterator>::value_type, typename benchmark::State::StateIterator::value_type>::value, ""); +} // end namespace BENCHMARK_MAIN(); diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index 5e25aa9ee7..dedcbe6fa3 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -1,7 +1,6 @@ #include #include #include -#include #include #include @@ -35,12 +34,12 @@ class TestReporter : public benchmark::ConsoleReporter { std::vector iter_nums_; }; -} // end namespace - -static void BM_MyBench(benchmark::State& state) { +void BM_MyBench(benchmark::State& state) { for (auto s : state) { } } +} // end namespace + BENCHMARK(BM_MyBench); int main(int argc, char** argv) { diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index 8d221e41ba..bbc2cc35d8 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -60,14 +60,14 @@ void DoTestHelper(int* argc, const char** argv, double expected) { assert(!min_times.empty() && AlmostEqual(min_times[0], expected)); } -} // end namespace - -static void BM_MyBench(benchmark::State& state) { +void BM_MyBench(benchmark::State& state) { for (auto s : state) { } } BENCHMARK(BM_MyBench); +} // end namespace + int main(int argc, char** argv) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index 53695e9886..eb45a73e92 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include "benchmark/benchmark.h" @@ -48,19 +46,18 @@ static std::atomic setup_call(0); static std::atomic teardown_call(0); static std::atomic func_call(0); } // namespace concurrent -} // namespace -static void DoSetup2(const benchmark::State& state) { +void DoSetup2(const benchmark::State& state) { concurrent::setup_call.fetch_add(1, std::memory_order_acquire); assert(state.thread_index() == 0); } -static void DoTeardown2(const benchmark::State& state) { +void DoTeardown2(const benchmark::State& state) { concurrent::teardown_call.fetch_add(1, std::memory_order_acquire); assert(state.thread_index() == 0); } -static void BM_concurrent(benchmark::State& state) { +void BM_concurrent(benchmark::State& state) { for (auto s : state) { } concurrent::func_call.fetch_add(1, std::memory_order_acquire); @@ -75,12 +72,10 @@ BENCHMARK(BM_concurrent) ->Threads(15); // Testing interaction with Fixture::Setup/Teardown -namespace { namespace fixture_interaction { int setup = 0; int fixture_setup = 0; } // namespace fixture_interaction -} // namespace #define FIXTURE_BECHMARK_NAME MyFixture @@ -98,7 +93,7 @@ BENCHMARK_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)(benchmark::State& st) { } } -static void DoSetupWithFixture(const benchmark::State& /*unused*/) { +void DoSetupWithFixture(const benchmark::State& /*unused*/) { fixture_interaction::setup++; } @@ -116,10 +111,10 @@ namespace repetitions { int setup = 0; } -static void DoSetupWithRepetitions(const benchmark::State& /*unused*/) { +void DoSetupWithRepetitions(const benchmark::State& /*unused*/) { repetitions::setup++; } -static void BM_WithRep(benchmark::State& state) { +void BM_WithRep(benchmark::State& state) { for (auto _ : state) { } } @@ -132,6 +127,7 @@ BENCHMARK(BM_WithRep) ->Setup(DoSetupWithRepetitions) ->Iterations(100) ->Repetitions(4); +} // namespace int main(int argc, char** argv) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index 141f286fea..49cbfba6f3 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -8,9 +8,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -56,9 +54,7 @@ std::mutex test_vector_mu; std::optional> test_vector; // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) -} // end namespace - -static void BM_Factorial(benchmark::State& state) { +void BM_Factorial(benchmark::State& state) { int fac_42 = 0; for (auto _ : state) { fac_42 = Factorial(8); @@ -71,7 +67,7 @@ static void BM_Factorial(benchmark::State& state) { BENCHMARK(BM_Factorial); BENCHMARK(BM_Factorial)->UseRealTime(); -static void BM_CalculatePiRange(benchmark::State& state) { +void BM_CalculatePiRange(benchmark::State& state) { double pi = 0.0; for (auto _ : state) { pi = CalculatePi(static_cast(state.range(0))); @@ -82,7 +78,7 @@ static void BM_CalculatePiRange(benchmark::State& state) { } BENCHMARK_RANGE(BM_CalculatePiRange, 1, 1024 * 1024); -static void BM_CalculatePi(benchmark::State& state) { +void BM_CalculatePi(benchmark::State& state) { static const int depth = 1024; for (auto _ : state) { double pi = CalculatePi(static_cast(depth)); @@ -93,7 +89,7 @@ BENCHMARK(BM_CalculatePi)->Threads(8); BENCHMARK(BM_CalculatePi)->ThreadRange(1, 32); BENCHMARK(BM_CalculatePi)->ThreadPerCpu(); -static void BM_SetInsert(benchmark::State& state) { +void BM_SetInsert(benchmark::State& state) { std::set data; for (auto _ : state) { state.PauseTiming(); @@ -115,7 +111,7 @@ BENCHMARK(BM_SetInsert)->Ranges({{1 << 10, 8 << 10}, {128, 512}}); template -static void BM_Sequential(benchmark::State& state) { +void BM_Sequential(benchmark::State& state) { ValueType v = 42; for (auto _ : state) { Container c; @@ -133,7 +129,7 @@ BENCHMARK_TEMPLATE(BM_Sequential, std::list)->Range(1 << 0, 1 << 10); // Test the variadic version of BENCHMARK_TEMPLATE in C++11 and beyond. BENCHMARK_TEMPLATE(BM_Sequential, std::vector, int)->Arg(512); -static void BM_StringCompare(benchmark::State& state) { +void BM_StringCompare(benchmark::State& state) { size_t len = static_cast(state.range(0)); std::string s1(len, '-'); std::string s2(len, '-'); @@ -144,7 +140,7 @@ static void BM_StringCompare(benchmark::State& state) { } BENCHMARK(BM_StringCompare)->Range(1, 1 << 20); -static void BM_SetupTeardown(benchmark::State& state) { +void BM_SetupTeardown(benchmark::State& state) { if (state.thread_index() == 0) { // No need to lock test_vector_mu here as this is running single-threaded. test_vector = std::vector(); @@ -165,7 +161,7 @@ static void BM_SetupTeardown(benchmark::State& state) { } BENCHMARK(BM_SetupTeardown)->ThreadPerCpu(); -static void BM_LongTest(benchmark::State& state) { +void BM_LongTest(benchmark::State& state) { double tracker = 0.0; for (auto _ : state) { for (int i = 0; i < state.range(0); ++i) { @@ -175,7 +171,7 @@ static void BM_LongTest(benchmark::State& state) { } BENCHMARK(BM_LongTest)->Range(1 << 16, 1 << 28); -static void BM_ParallelMemset(benchmark::State& state) { +void BM_ParallelMemset(benchmark::State& state) { int64_t size = state.range(0) / static_cast(sizeof(int)); int thread_size = static_cast(size) / state.threads(); int from = thread_size * state.thread_index(); @@ -199,7 +195,7 @@ static void BM_ParallelMemset(benchmark::State& state) { } BENCHMARK(BM_ParallelMemset)->Arg(10 << 20)->ThreadRange(1, 4); -static void BM_ManualTiming(benchmark::State& state) { +void BM_ManualTiming(benchmark::State& state) { int64_t slept_for = 0; int64_t microseconds = state.range(0); std::chrono::duration sleep_duration{ @@ -263,7 +259,7 @@ void BM_template1_capture(benchmark::State& state, ExtraArgs&&... extra_args) { BENCHMARK_TEMPLATE1_CAPTURE(BM_template1_capture, void, foo, 24UL); BENCHMARK_CAPTURE(BM_template1_capture, foo, 24UL); -static void BM_DenseThreadRanges(benchmark::State& st) { +void BM_DenseThreadRanges(benchmark::State& st) { switch (st.range(0)) { case 1: assert(st.threads() == 1 || st.threads() == 2 || st.threads() == 3); @@ -285,7 +281,7 @@ BENCHMARK(BM_DenseThreadRanges)->Arg(1)->DenseThreadRange(1, 3); BENCHMARK(BM_DenseThreadRanges)->Arg(2)->DenseThreadRange(1, 4, 2); BENCHMARK(BM_DenseThreadRanges)->Arg(3)->DenseThreadRange(5, 14, 3); -static void BM_BenchmarkName(benchmark::State& state) { +void BM_BenchmarkName(benchmark::State& state) { for (auto _ : state) { } @@ -296,15 +292,15 @@ BENCHMARK(BM_BenchmarkName); // regression test for #1446 template -static void BM_templated_test(benchmark::State& state) { +void BM_templated_test(benchmark::State& state) { for (auto _ : state) { type created_string; benchmark::DoNotOptimize(created_string); } } -static const auto BM_templated_test_double = - BM_templated_test>; +const auto BM_templated_test_double = BM_templated_test>; BENCHMARK(BM_templated_test_double); +} // end namespace BENCHMARK_MAIN(); diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 23c5f3e519..8cf17f41d3 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -1,5 +1,4 @@ #undef NDEBUG -#include #include #include #include @@ -13,10 +12,10 @@ namespace { #define ADD_COMPLEXITY_CASES(...) \ const int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__) -int AddComplexityTest(const std::string &test_name, - const std::string &big_o_test_name, - const std::string &rms_test_name, - const std::string &big_o, int family_index) { +int AddComplexityTest(const std::string& test_name, + const std::string& big_o_test_name, + const std::string& rms_test_name, + const std::string& big_o, int family_index) { SetSubstitutions({{"%name", test_name}, {"%bigo_name", big_o_test_name}, {"%rms_name", rms_test_name}, @@ -61,13 +60,11 @@ int AddComplexityTest(const std::string &test_name, return 0; } -} // end namespace - // ========================================================================= // // --------------------------- Testing BigO O(1) --------------------------- // // ========================================================================= // -void BM_Complexity_O1(benchmark::State &state) { +void BM_Complexity_O1(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); @@ -116,7 +113,7 @@ ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, // --------------------------- Testing BigO O(N) --------------------------- // // ========================================================================= // -void BM_Complexity_O_N(benchmark::State &state) { +void BM_Complexity_O_N(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); @@ -173,8 +170,8 @@ ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name, // ------------------------- Testing BigO O(NlgN) ------------------------- // // ========================================================================= // -static const double kLog2E = 1.44269504088896340736; -static void BM_Complexity_O_N_log_N(benchmark::State &state) { +const double kLog2E = 1.44269504088896340736; +void BM_Complexity_O_N_log_N(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); @@ -236,7 +233,7 @@ ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, // -------- Testing formatting of Complexity with captured args ------------ // // ========================================================================= // -void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { +void BM_ComplexityCaptureArgs(benchmark::State& state, int n) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero benchmark::DoNotOptimize(state.iterations()); @@ -264,12 +261,13 @@ const std::string complexity_capture_name = ADD_COMPLEXITY_CASES(complexity_capture_name, complexity_capture_name + "_BigO", complexity_capture_name + "_RMS", "N", /*family_index=*/9); +} // end namespace // ========================================================================= // // --------------------------- TEST CASES END ------------------------------ // // ========================================================================= // -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); RunOutputTests(argc, argv); } diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index e930f024e9..e8d7d9119a 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -17,6 +17,7 @@ #define TEST_HAS_NO_EXCEPTIONS #endif +namespace { void TestHandler() { #ifndef TEST_HAS_NO_EXCEPTIONS throw std::logic_error(""); @@ -84,6 +85,7 @@ void BM_diagnostic_test_keep_running(benchmark::State& state) { called_once = true; } BENCHMARK(BM_diagnostic_test_keep_running); +} // end namespace int main(int argc, char* argv[]) { #ifdef NDEBUG diff --git a/test/display_aggregates_only_test.cc b/test/display_aggregates_only_test.cc index 1d3b6cd2df..bae97593ac 100644 --- a/test/display_aggregates_only_test.cc +++ b/test/display_aggregates_only_test.cc @@ -10,11 +10,13 @@ // reporter in the presence of DisplayAggregatesOnly(). // We do not care about console output, the normal tests check that already. +namespace { void BM_SummaryRepeat(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->DisplayAggregatesOnly(); +} // end namespace int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/donotoptimize_assembly_test.cc b/test/donotoptimize_assembly_test.cc index dc286f53e2..1f817e02bb 100644 --- a/test/donotoptimize_assembly_test.cc +++ b/test/donotoptimize_assembly_test.cc @@ -2,6 +2,7 @@ #ifdef __clang__ #pragma clang diagnostic ignored "-Wreturn-type" +#pragma clang diagnostic ignored "-Wmissing-prototypes" #endif BENCHMARK_DISABLE_DEPRECATED_WARNING @@ -19,7 +20,7 @@ inline int Add42(int x) { return x + 42; } struct NotTriviallyCopyable { NotTriviallyCopyable(); explicit NotTriviallyCopyable(int x) : value(x) {} - NotTriviallyCopyable(NotTriviallyCopyable const &); + NotTriviallyCopyable(NotTriviallyCopyable const&); int value; }; @@ -185,7 +186,7 @@ extern "C" void test_pointer_const_lvalue() { // CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z]+]]) // CHECK: ret int x = 42; - int *const xp = &x; + int* const xp = &x; benchmark::DoNotOptimize(xp); } @@ -196,6 +197,6 @@ extern "C" void test_pointer_lvalue() { // CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z+]+]]) // CHECK: ret int x = 42; - int *xp = &x; + int* xp = &x; benchmark::DoNotOptimize(xp); } diff --git a/test/filter_test.cc b/test/filter_test.cc index 0a4a1df6c5..8c150eb2de 100644 --- a/test/filter_test.cc +++ b/test/filter_test.cc @@ -37,37 +37,36 @@ class TestReporter : public benchmark::ConsoleReporter { mutable int64_t max_family_index_; }; -} // end namespace - -static void NoPrefix(benchmark::State& state) { +void NoPrefix(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(NoPrefix); -static void BM_Foo(benchmark::State& state) { +void BM_Foo(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_Foo); -static void BM_Bar(benchmark::State& state) { +void BM_Bar(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_Bar); -static void BM_FooBar(benchmark::State& state) { +void BM_FooBar(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_FooBar); -static void BM_FooBa(benchmark::State& state) { +void BM_FooBa(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_FooBa); +} // end namespace int main(int argc, char** argv) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/internal_threading_test.cc b/test/internal_threading_test.cc index d2897e7212..c57bf44b0c 100644 --- a/test/internal_threading_test.cc +++ b/test/internal_threading_test.cc @@ -8,8 +8,9 @@ #include "benchmark/benchmark.h" #include "output_test.h" -static const std::chrono::duration time_frame(50); -static const double time_frame_in_sec( +namespace { +const std::chrono::duration time_frame(50); +const double time_frame_in_sec( std::chrono::duration_cast>>( time_frame) .count()); @@ -178,6 +179,7 @@ BENCHMARK(BM_MainThreadAndWorkerThread) ->Threads(2) ->MeasureProcessCPUTime() ->UseManualTime(); +} // end namespace // ========================================================================= // // ---------------------------- TEST CASES END ----------------------------- // diff --git a/test/link_main_test.cc b/test/link_main_test.cc index b0a37c06e1..41dbac9ab0 100644 --- a/test/link_main_test.cc +++ b/test/link_main_test.cc @@ -1,5 +1,6 @@ #include "benchmark/benchmark.h" +namespace { void BM_empty(benchmark::State& state) { for (auto _ : state) { auto iterations = static_cast(state.iterations()) * @@ -8,3 +9,4 @@ void BM_empty(benchmark::State& state) { } } BENCHMARK(BM_empty); +} // end namespace diff --git a/test/locale_impermeability_test.cc b/test/locale_impermeability_test.cc index b98eb53930..e2dd6cfd9d 100644 --- a/test/locale_impermeability_test.cc +++ b/test/locale_impermeability_test.cc @@ -1,14 +1,13 @@ #undef NDEBUG -#include #include #include #include -#include #include "benchmark/benchmark.h" #include "output_test.h" -static void BM_ostream(benchmark::State &state) { +namespace { +void BM_ostream(benchmark::State& state) { #if !defined(__MINGW64__) || defined(__clang__) // GCC-based versions of MINGW64 do not support locale manipulations, // don't run the test under them. @@ -40,8 +39,9 @@ ADD_CASES(TC_JSONOut, {"}", MR_Next}}); ADD_CASES(TC_CSVOut, {{"^\"BM_ostream/iterations:1000000/" "manual_time\",1000000,%float,%float,ns,,,,,$"}}); +} // end namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); RunOutputTests(argc, argv); } diff --git a/test/map_test.cc b/test/map_test.cc index 216ed0334a..018e12a75e 100644 --- a/test/map_test.cc +++ b/test/map_test.cc @@ -13,10 +13,8 @@ std::map ConstructRandomMap(int size) { return m; } -} // namespace - // Basic version. -static void BM_MapLookup(benchmark::State& state) { +void BM_MapLookup(benchmark::State& state) { const int size = static_cast(state.range(0)); std::map m; for (auto _ : state) { @@ -31,6 +29,7 @@ static void BM_MapLookup(benchmark::State& state) { state.SetItemsProcessed(state.iterations() * size); } BENCHMARK(BM_MapLookup)->Range(1 << 3, 1 << 12); +} // namespace // Using fixtures. class MapFixture : public ::benchmark::Fixture { diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index f9b9021892..39b32169d5 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -1,9 +1,9 @@ #include -#include "../src/check.h" #include "benchmark/benchmark.h" #include "output_test.h" +namespace { class TestMemoryManager : public benchmark::MemoryManager { void Start() override {} void Stop(Result& result) override { @@ -20,6 +20,7 @@ void BM_empty(benchmark::State& state) { } } BENCHMARK(BM_empty); +} // end namespace ADD_CASES(TC_ConsoleOut, {{"^BM_empty %console_report$"}}); ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"}, diff --git a/test/multiple_ranges_test.cc b/test/multiple_ranges_test.cc index 5300a96036..987b69c82f 100644 --- a/test/multiple_ranges_test.cc +++ b/test/multiple_ranges_test.cc @@ -5,6 +5,7 @@ #include "benchmark/benchmark.h" +namespace { class MultipleRangesFixture : public ::benchmark::Fixture { public: MultipleRangesFixture() @@ -87,10 +88,11 @@ void BM_CheckDefaultArgument(benchmark::State& state) { } BENCHMARK(BM_CheckDefaultArgument)->Ranges({{1, 5}, {6, 10}}); -static void BM_MultipleRanges(benchmark::State& st) { +void BM_MultipleRanges(benchmark::State& st) { for (auto _ : st) { } } BENCHMARK(BM_MultipleRanges)->Ranges({{5, 5}, {6, 6}}); +} // end namespace BENCHMARK_MAIN(); diff --git a/test/options_test.cc b/test/options_test.cc index a1b209f3eb..f9dc59b040 100644 --- a/test/options_test.cc +++ b/test/options_test.cc @@ -8,6 +8,7 @@ #endif #include +namespace { void BM_basic(benchmark::State& state) { for (auto _ : state) { } @@ -73,5 +74,6 @@ void BM_explicit_iteration_count(benchmark::State& state) { assert(state.iterations() == 42); } BENCHMARK(BM_explicit_iteration_count)->Iterations(42); +} // end namespace BENCHMARK_MAIN(); diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index a0898be90c..43a1bfde87 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -209,12 +209,14 @@ class ResultsChecker { std::vector SplitCsv_(const std::string& line) const; }; +namespace { // store the static ResultsChecker in a function to prevent initialization // order problems ResultsChecker& GetResultsChecker() { static ResultsChecker rc; return rc; } +} // end namespace // add a results checker for a benchmark void ResultsChecker::Add(const std::string& entry_pattern, @@ -489,18 +491,19 @@ int SubstrCnt(const std::string& haystack, const std::string& pat) { return count; } -static char ToHex(int ch) { +namespace { +char ToHex(int ch) { return ch < 10 ? static_cast('0' + ch) : static_cast('a' + (ch - 10)); } -static char RandomHexChar() { +char RandomHexChar() { static std::mt19937 rd{std::random_device{}()}; static std::uniform_int_distribution mrand{0, 15}; return ToHex(mrand(rd)); } -static std::string GetRandomFileName() { +std::string GetRandomFileName() { std::string model = "test.%%%%%%"; for (auto& ch : model) { if (ch == '%') { @@ -510,12 +513,12 @@ static std::string GetRandomFileName() { return model; } -static bool FileExists(std::string const& name) { +bool FileExists(std::string const& name) { std::ifstream in(name.c_str()); return in.good(); } -static std::string GetTempFileName() { +std::string GetTempFileName() { // This function attempts to avoid race conditions where two tests // create the same file at the same time. However, it still introduces races // similar to tmpnam. @@ -530,6 +533,7 @@ static std::string GetTempFileName() { std::flush(std::cerr); std::exit(1); } +} // end namespace std::string GetFileReporterOutput(int argc, char* argv[]) { std::vector new_argv(argv, argv + argc); diff --git a/test/overload_gtest.cc b/test/overload_gtest.cc index 5ca11a9dc6..d1fee9a783 100644 --- a/test/overload_gtest.cc +++ b/test/overload_gtest.cc @@ -1,9 +1,10 @@ #include "benchmark/benchmark.h" +namespace { // Simulate an overloaded function name. // This version does nothing and is just here to create ambiguity for // MyOverloadedBenchmark. -void MyOverloadedBenchmark() {} +BENCHMARK_UNUSED void MyOverloadedBenchmark() {} // This is the actual benchmark function we want to register. // It has the signature void(benchmark::State&) required by the library. @@ -29,5 +30,6 @@ void MyTemplatedOverloadedBenchmark(benchmark::State& state) { } BENCHMARK_TEMPLATE(MyTemplatedOverloadedBenchmark, 1); +} // end namespace BENCHMARK_MAIN(); diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index 8aa3a7b632..a830b5ef10 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -11,8 +11,9 @@ namespace benchmark { BM_DECLARE_string(benchmark_perf_counters); } // namespace benchmark +namespace { -static void BM_Simple(benchmark::State& state) { +void BM_Simple(benchmark::State& state) { for (auto _ : state) { auto iterations = double(state.iterations()) * double(state.iterations()); benchmark::DoNotOptimize(iterations); @@ -66,17 +67,18 @@ static void CheckSimple(Results const& e) { double withoutPauseResumeInstrCount = 0.0; double withPauseResumeInstrCount = 0.0; -static void SaveInstrCountWithoutResume(Results const& e) { +void SaveInstrCountWithoutResume(Results const& e) { withoutPauseResumeInstrCount = e.GetAs("INSTRUCTIONS"); } -static void SaveInstrCountWithResume(Results const& e) { +void SaveInstrCountWithResume(Results const& e) { withPauseResumeInstrCount = e.GetAs("INSTRUCTIONS"); } CHECK_BENCHMARK_RESULTS("BM_Simple", &CheckSimple); CHECK_BENCHMARK_RESULTS("BM_WithoutPauseResume", &SaveInstrCountWithoutResume); CHECK_BENCHMARK_RESULTS("BM_WithPauseResume", &SaveInstrCountWithResume); +} // end namespace int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/profiler_manager_iterations_test.cc b/test/profiler_manager_iterations_test.cc index af1052f7a5..c4983eb348 100644 --- a/test/profiler_manager_iterations_test.cc +++ b/test/profiler_manager_iterations_test.cc @@ -25,14 +25,13 @@ class NullReporter : public benchmark::BenchmarkReporter { void ReportRuns(const std::vector& /* report */) override {} }; -} // end namespace - -static void BM_MyBench(benchmark::State& state) { +void BM_MyBench(benchmark::State& state) { for (auto s : state) { ++iteration_count; } } BENCHMARK(BM_MyBench); +} // end namespace int main(int argc, char** argv) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc index 75a2aaa50b..5c4b14daa3 100644 --- a/test/profiler_manager_test.cc +++ b/test/profiler_manager_test.cc @@ -6,6 +6,7 @@ #include "benchmark/benchmark.h" #include "output_test.h" +namespace { class TestProfilerManager : public benchmark::ProfilerManager { public: void AfterSetupStart() override { ++start_called; } @@ -38,6 +39,7 @@ ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"}, {"\"time_unit\": \"ns\"$", MR_Next}, {"}", MR_Next}}); ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}}); +} // end namespace int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index e91ba97663..e6f24c2ade 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -56,8 +56,6 @@ int AddCases(std::initializer_list const& v) { #define ADD_CASES(...) \ const int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__}) -} // end namespace - using ReturnVal = benchmark::internal::Benchmark const* const; //----------------------------------------------------------------------------// @@ -182,6 +180,7 @@ void RunTestTwo() { } assert(EB == ExpectedResults.end()); } +} // end namespace int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/repetitions_test.cc b/test/repetitions_test.cc index 9a7dcc3015..9116fa65be 100644 --- a/test/repetitions_test.cc +++ b/test/repetitions_test.cc @@ -2,11 +2,12 @@ #include "benchmark/benchmark.h" #include "output_test.h" +namespace { // ========================================================================= // // ------------------------ Testing Basic Output --------------------------- // // ========================================================================= // -static void BM_ExplicitRepetitions(benchmark::State& state) { +void BM_ExplicitRepetitions(benchmark::State& state) { for (auto _ : state) { } } @@ -108,7 +109,7 @@ ADD_CASES(TC_CSVOut, // ------------------------ Testing Basic Output --------------------------- // // ========================================================================= // -static void BM_ImplicitRepetitions(benchmark::State& state) { +void BM_ImplicitRepetitions(benchmark::State& state) { for (auto _ : state) { } } @@ -206,6 +207,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions\",%csv_report$"}}); ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_mean\",%csv_report$"}}); ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_median\",%csv_report$"}}); ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_stddev\",%csv_report$"}}); +} // end namespace // ========================================================================= // // --------------------------- TEST CASES END ------------------------------ // diff --git a/test/report_aggregates_only_test.cc b/test/report_aggregates_only_test.cc index d907559073..707d92383a 100644 --- a/test/report_aggregates_only_test.cc +++ b/test/report_aggregates_only_test.cc @@ -6,6 +6,7 @@ #include "benchmark/benchmark.h" #include "output_test.h" +namespace { // Ok this test is super ugly. We want to check what happens with the file // reporter in the presence of ReportAggregatesOnly(). // We do not care about console output, the normal tests check that already. @@ -15,6 +16,7 @@ void BM_SummaryRepeat(benchmark::State& state) { } } BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->ReportAggregatesOnly(); +} // end namespace int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 58860ca0b0..9940ab75de 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -1,11 +1,9 @@ - #undef NDEBUG -#include -#include #include "benchmark/benchmark.h" #include "output_test.h" +namespace { // ========================================================================= // // ---------------------- Testing Prologue Output -------------------------- // // ========================================================================= // @@ -13,7 +11,7 @@ ADD_CASES(TC_ConsoleOut, {{"^[-]+$", MR_Next}, {"^Benchmark %s Time %s CPU %s Iterations$", MR_Next}, {"^[-]+$", MR_Next}}); -static int AddContextCases() { +int AddContextCases() { AddCases(TC_ConsoleErr, { {"^%int-%int-%intT%int:%int:%int[-+]%int:%int$", MR_Default}, @@ -1128,6 +1126,7 @@ void BM_CSV_Format(benchmark::State& state) { } BENCHMARK(BM_CSV_Format); ADD_CASES(TC_CSVOut, {{"^\"BM_CSV_Format\",,,,,,,,true,\"\"\"freedom\"\"\"$"}}); +} // end namespace // ========================================================================= // // --------------------------- TEST CASES END ------------------------------ // diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 7553eba3f9..425895988c 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -62,8 +62,6 @@ int AddCases(const std::string& base_name, #define CONCAT2(x, y) x##y #define ADD_CASES(...) const int CONCAT(dummy, __LINE__) = AddCases(__VA_ARGS__) -} // end namespace - void BM_error_no_running(benchmark::State& state) { state.SkipWithError("error message"); } @@ -182,6 +180,16 @@ ADD_CASES("BM_error_while_paused", {{"/1/threads:1", true, "error message"}, {"/2/threads:4", false, ""}, {"/2/threads:8", false, ""}}); +void BM_malformed(benchmark::State& /*unused*/) { + // NOTE: empty body wanted. No thing else. +} +BENCHMARK(BM_malformed); +ADD_CASES("BM_malformed", + {{"", true, + "The benchmark didn't run, nor was it explicitly skipped. Please " + "call 'SkipWithXXX` in your benchmark as appropriate."}}); +} // end namespace + int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); benchmark::Initialize(&argc, argv); @@ -201,12 +209,3 @@ int main(int argc, char* argv[]) { return 0; } - -void BM_malformed(benchmark::State&) { - // NOTE: empty body wanted. No thing else. -} -BENCHMARK(BM_malformed); -ADD_CASES("BM_malformed", - {{"", true, - "The benchmark didn't run, nor was it explicitly skipped. Please " - "call 'SkipWithXXX` in your benchmark as appropriate."}}); diff --git a/test/spec_arg_test.cc b/test/spec_arg_test.cc index cec5c32ee8..21275ef0d8 100644 --- a/test/spec_arg_test.cc +++ b/test/spec_arg_test.cc @@ -39,21 +39,21 @@ class TestReporter : public benchmark::ConsoleReporter { std::vector matched_functions; }; -} // end namespace - -static void BM_NotChosen(benchmark::State& state) { +void BM_NotChosen(benchmark::State& state) { assert(false && "SHOULD NOT BE CALLED"); for (auto _ : state) { } } BENCHMARK(BM_NotChosen); -static void BM_Chosen(benchmark::State& state) { +void BM_Chosen(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_Chosen); +} // end namespace + int main(int argc, char** argv) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/spec_arg_verbosity_test.cc b/test/spec_arg_verbosity_test.cc index 43dfda9d55..318784cfff 100644 --- a/test/spec_arg_verbosity_test.cc +++ b/test/spec_arg_verbosity_test.cc @@ -4,12 +4,14 @@ #include "benchmark/benchmark.h" +namespace { // Tests that the user specified verbosity level can be get. -static void BM_Verbosity(benchmark::State& state) { +void BM_Verbosity(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_Verbosity); +} // end namespace int main(int argc, char** argv) { benchmark::MaybeReenterWithoutASLR(argc, argv); diff --git a/test/state_assembly_test.cc b/test/state_assembly_test.cc index 7ddbb3b2a9..e9ecfebf16 100644 --- a/test/state_assembly_test.cc +++ b/test/state_assembly_test.cc @@ -2,6 +2,7 @@ #ifdef __clang__ #pragma clang diagnostic ignored "-Wreturn-type" +#pragma clang diagnostic ignored "-Wmissing-prototypes" #endif // clang-format off diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index 0046210bcf..d53ffdc48b 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -4,6 +4,7 @@ #include "benchmark/benchmark.h" #include "output_test.h" +namespace { // @todo: this checks the full output at once; the rule for // CounterSet1 was failing because it was not matching "^[-]+$". // @todo: check that the counters are vertically aligned. @@ -555,6 +556,7 @@ void CheckSet2(Results const& e) { CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 40); } CHECK_BENCHMARK_RESULTS("BM_CounterSet2_Tabular", &CheckSet2); +} // end namespace // ========================================================================= // // --------------------------- TEST CASES END ------------------------------ // diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index 910f9300b2..c55ad98bf2 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -21,7 +21,7 @@ ADD_CASES(TC_CSVOut, {{"%csv_header,\"bar\",\"foo\""}}); // ========================================================================= // // ------------------------- Simple Counters Output ------------------------ // // ========================================================================= // - +namespace { void BM_Counters_Simple(benchmark::State& state) { for (auto _ : state) { } @@ -56,6 +56,7 @@ void CheckSimple(Results const& e) { CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its, 0.001); } CHECK_BENCHMARK_RESULTS("BM_Counters_Simple", &CheckSimple); +} // end namespace // ========================================================================= // // --------------------- Counters+Items+Bytes/s Output --------------------- // @@ -63,7 +64,6 @@ CHECK_BENCHMARK_RESULTS("BM_Counters_Simple", &CheckSimple); namespace { int num_calls1 = 0; -} void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero @@ -112,11 +112,12 @@ void CheckBytesAndItemsPSec(Results const& e) { } CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec", &CheckBytesAndItemsPSec); +} // end namespace // ========================================================================= // // ------------------------- Rate Counters Output -------------------------- // // ========================================================================= // - +namespace { void BM_Counters_Rate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero @@ -157,11 +158,13 @@ void CheckRate(Results const& e) { CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001); } CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate); +} // end namespace // ========================================================================= // // ----------------------- Inverted Counters Output ------------------------ // // ========================================================================= // +namespace { void BM_Invert(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero @@ -199,11 +202,13 @@ void CheckInvert(Results const& e) { CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 0.0001, 0.0001); } CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert); +} // end namespace // ========================================================================= // // --------------------- InvertedRate Counters Output ---------------------- // // ========================================================================= // +namespace { void BM_Counters_InvertedRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero @@ -247,11 +252,13 @@ void CheckInvertedRate(Results const& e) { CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / 8192.0, 0.001); } CHECK_BENCHMARK_RESULTS("BM_Counters_InvertedRate", &CheckInvertedRate); +} // end namespace // ========================================================================= // // ------------------------- Thread Counters Output ------------------------ // // ========================================================================= // +namespace { void BM_Counters_Threads(benchmark::State& state) { for (auto _ : state) { } @@ -287,11 +294,13 @@ void CheckThreads(Results const& e) { CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2 * e.NumThreads()); } CHECK_BENCHMARK_RESULTS("BM_Counters_Threads/threads:%int", &CheckThreads); +} // end namespace // ========================================================================= // // ---------------------- ThreadAvg Counters Output ------------------------ // // ========================================================================= // +namespace { void BM_Counters_AvgThreads(benchmark::State& state) { for (auto _ : state) { } @@ -329,11 +338,13 @@ void CheckAvgThreads(Results const& e) { } CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int", &CheckAvgThreads); +} // end namespace // ========================================================================= // // ---------------------- ThreadAvg Counters Output ------------------------ // // ========================================================================= // +namespace { void BM_Counters_AvgThreadsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero @@ -375,11 +386,13 @@ void CheckAvgThreadsRate(Results const& e) { } CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int", &CheckAvgThreadsRate); +} // end namespace // ========================================================================= // // ------------------- IterationInvariant Counters Output ------------------ // // ========================================================================= // +namespace { void BM_Counters_IterationInvariant(benchmark::State& state) { for (auto _ : state) { } @@ -418,11 +431,13 @@ void CheckIterationInvariant(Results const& e) { } CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant", &CheckIterationInvariant); +} // end namespace // ========================================================================= // // ----------------- IterationInvariantRate Counters Output ---------------- // // ========================================================================= // +namespace { void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero @@ -469,11 +484,13 @@ void CheckIsIterationInvariantRate(Results const& e) { } CHECK_BENCHMARK_RESULTS("BM_Counters_kIsIterationInvariantRate", &CheckIsIterationInvariantRate); +} // end namespace // ========================================================================= // // --------------------- AvgIterations Counters Output --------------------- // // ========================================================================= // +namespace { void BM_Counters_AvgIterations(benchmark::State& state) { for (auto _ : state) { } @@ -511,11 +528,13 @@ void CheckAvgIterations(Results const& e) { CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / its, 0.001); } CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations", &CheckAvgIterations); +} // end namespace // ========================================================================= // // ------------------- AvgIterationsRate Counters Output ------------------- // // ========================================================================= // +namespace { void BM_Counters_kAvgIterationsRate(benchmark::State& state) { for (auto _ : state) { // This test requires a non-zero CPU time to avoid divide-by-zero @@ -560,6 +579,7 @@ void CheckAvgIterationsRate(Results const& e) { } CHECK_BENCHMARK_RESULTS("BM_Counters_kAvgIterationsRate", &CheckAvgIterationsRate); +} // end namespace // ========================================================================= // // --------------------------- TEST CASES END ------------------------------ // diff --git a/test/user_counters_thousands_test.cc b/test/user_counters_thousands_test.cc index 4f341db5da..0ef78d3787 100644 --- a/test/user_counters_thousands_test.cc +++ b/test/user_counters_thousands_test.cc @@ -4,6 +4,7 @@ #include "benchmark/benchmark.h" #include "output_test.h" +namespace { // ========================================================================= // // ------------------------ Thousands Customisation ------------------------ // // ========================================================================= // @@ -179,6 +180,7 @@ void CheckThousands(Results const& e) { CHECK_FLOAT_COUNTER_VALUE(e, "t4_1048576Base1024", EQ, 1024 * 1024, 0.0001); } CHECK_BENCHMARK_RESULTS("BM_Counters_Thousands", &CheckThousands); +} // end namespace // ========================================================================= // // --------------------------- TEST CASES END ------------------------------ // From a61c3a6509925a7bb7dd39d1e8c2e34fc53742b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:55:15 +0000 Subject: [PATCH 414/561] Bump actions/upload-artifact from 4.6.2 to 5.0.0 (#2063) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 5.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...330a01c490aca151604b8cf639adc76d48f6c5d4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 3a092565d5..ba26c8a0f1 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -25,7 +25,7 @@ jobs: - run: python -m pip install build - name: Build sdist run: python -m build --sdist - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: dist-sdist path: dist/*.tar.gz @@ -64,7 +64,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-15-intel' && 10.14 || 11.0 }} - name: Upload Google Benchmark ${{ matrix.os }} wheels - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: dist-${{ matrix.os }} path: wheelhouse/*.whl From 8ece01661a8f67b69458e4738602248aa10960b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:04:28 +0000 Subject: [PATCH 415/561] Bump actions/download-artifact from 5.0.0 to 6.0.0 (#2064) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/634f93cb2916e3fdff6788551b99b062d0335ce0...018cc2cf5baa6db3ef3c5f8a56943fffe632ef53) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index ba26c8a0f1..2a5dec933e 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -76,7 +76,7 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: path: dist pattern: dist-* From cd6bbba29c0f019a825d5bf1ab3e42468c8e6913 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:18:09 +0000 Subject: [PATCH 416/561] Bump astral-sh/setup-uv from 7.1.1 to 7.1.2 (#2065) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.1 to 7.1.2. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/2ddd2b9cb38ad8efd50337e8ab201519a34c9f24...85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 0ee9f893d7..bd16ddc996 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@2ddd2b9cb38ad8efd50337e8ab201519a34c9f24 # v7.1.1 + uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 2a5dec933e..b471dc346f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@2ddd2b9cb38ad8efd50337e8ab201519a34c9f24 # v7.1.1 + uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 From 18b746f813b1b65f7596e90af08f1b0178ae71a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:38:39 +0000 Subject: [PATCH 417/561] Bump scipy from 1.16.2 to 1.16.3 in /tools (#2066) Bumps [scipy](https://github.com/scipy/scipy) from 1.16.2 to 1.16.3. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.16.2...v1.16.3) --- updated-dependencies: - dependency-name: scipy dependency-version: 1.16.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 9999698040..8f969c30b5 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ numpy == 2.3.4 -scipy == 1.16.2 +scipy == 1.16.3 From 57d14f7048c04247fb12af7eff0a0cbd9c9b25d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 08:59:18 +0000 Subject: [PATCH 418/561] Bump astral-sh/setup-uv from 7.1.2 to 7.1.3 (#2068) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.2 to 7.1.3. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41...5a7eac68fb9809dea845d802897dc5c723910fa3) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index bd16ddc996..a7f8d1f488 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 + uses: astral-sh/setup-uv@5a7eac68fb9809dea845d802897dc5c723910fa3 # v7.1.3 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b471dc346f..8f612de1f3 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 + uses: astral-sh/setup-uv@5a7eac68fb9809dea845d802897dc5c723910fa3 # v7.1.3 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 From f87f080fb9722fd133a8790554060a48a684e9c6 Mon Sep 17 00:00:00 2001 From: Edge-Seven <143301646+Edge-Seven@users.noreply.github.com> Date: Mon, 17 Nov 2025 18:26:56 +0700 Subject: [PATCH 419/561] Fix typos in some files (#2070) Co-authored-by: khanhkhanhlele --- src/benchmark_register.cc | 2 +- src/benchmark_runner.cc | 2 +- src/perf_counters.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index d8cefe480c..854bc8344b 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -179,7 +179,7 @@ bool BenchmarkFamilies::FindBenchmarks( ++per_family_instance_index; - // Only bump the next family index once we've estabilished that + // Only bump the next family index once we've established that // at least one instance of this family will be run. if (next_family_index == family_index) { ++next_family_index; diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 0e7d4a792c..3cfa8a4e1e 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -400,7 +400,7 @@ bool BenchmarkRunner::ShouldReportIterationResults( } double BenchmarkRunner::GetMinTimeToApply() const { - // In order to re-use functionality to run and measure benchmarks for running + // In order to reuse functionality to run and measure benchmarks for running // a warmup phase of the benchmark, we need a way of telling whether to apply // min_time or min_warmup_time. This function will figure out if we are in the // warmup phase and therefore need to apply min_warmup_time or if we already diff --git a/src/perf_counters.cc b/src/perf_counters.cc index a2fa7fe35f..f47aa7b42d 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -214,7 +214,7 @@ PerfCounters PerfCounters::Create( // This should never happen but if it does, we give up on the // entire batch as recovery would be a mess. GetErrorLogInstance() << "***WARNING*** Failed to start counters. " - "Claring out all counters.\n"; + "Clearing out all counters.\n"; // Close all performance counters for (int id : counter_ids) { From 850b88b339b1d1278cde1c4f3c243f09b2306281 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 10:03:26 +0000 Subject: [PATCH 420/561] Bump actions/checkout from 5.0.0 to 5.0.1 (#2072) Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/08c6903cd8c0fde910a37f88322edcfb5dd907a8...93cb6efe18208431cddfb8368fd83d5badbf9bfd) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index ce8de66082..268b1c2702 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: mount bazel cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index f37b814f0b..0599ac43c1 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,7 +19,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: lukka/get-cmake@628dd514bed37cb0a609e84a6186cbbaa2fc0140 # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 0de759b93a..dbd45cb8ea 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5a368c04d2..58cef026ee 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,7 +30,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -77,7 +77,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: lukka/get-cmake@628dd514bed37cb0a609e84a6186cbbaa2fc0140 # latest @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 5e4f4b46fd..20e12031ce 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index 7a04d67d8a..8aeab2423c 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 56d315f2fa..fa02d6f21e 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index 496f348cea..f6e591f5a7 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Run analysis uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index a7f8d1f488..4dd21ecb16 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 61d331e06a..659bc9bce1 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: configure msan env if: matrix.sanitizer == 'msan' diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 1aab02f6e9..d1f00e38e5 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 8f612de1f3..f0762ffae5 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - name: Install Python 3.12 @@ -38,7 +38,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 From 0f0a272e074b740d9254c3471aad0cfe494bd926 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 10:20:13 +0000 Subject: [PATCH 421/561] Bump pypa/cibuildwheel from 3.2.1 to 3.3.0 (#2069) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.2.1 to 3.3.0. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/9c00cb4f6b517705a3794b22395aedc36257242c...63fd63b352a9a8bdcc24791c9dbee952ee9a8abc) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f0762ffae5..9756557560 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@5a7eac68fb9809dea845d802897dc5c723910fa3 # v7.1.3 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # v3.2.1 + uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From 6509ad7e4115bc52947849ec718930bf06602a67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 11:54:15 +0000 Subject: [PATCH 422/561] Bump numpy from 2.3.4 to 2.3.5 in /tools (#2071) Bumps [numpy](https://github.com/numpy/numpy) from 2.3.4 to 2.3.5. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.3.4...v2.3.5) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.3.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 8f969c30b5..419e2defb5 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.3.4 +numpy == 2.3.5 scipy == 1.16.3 From 9458f54b9abd7431eae1e81e777e631607e6bed3 Mon Sep 17 00:00:00 2001 From: wieDasDing <6884440+dingxiangfei2009@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:48:56 +0100 Subject: [PATCH 423/561] Take a closure for benchmark configuration (#2073) It turns out it is useful when a benchmark is generated on the fly before the enumeration on benchmark registration. There is a use case in which benchmarks shall be built from configuration flags. Without captures, it is actually hard to pass additional data. Signed-off-by: Xiangfei Ding --- include/benchmark/benchmark.h | 2 +- src/benchmark_register.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 8144518bd7..b6153e490e 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1229,7 +1229,7 @@ class BENCHMARK_EXPORT Benchmark { // Pass this benchmark object to *func, which can customize // the benchmark by calling various methods like Arg, Args, // Threads, etc. - Benchmark* Apply(void (*custom_arguments)(Benchmark* benchmark)); + Benchmark* Apply(const std::function&); // Set the range multiplier for non-dense range. If not called, the range // multiplier kRangeMultiplier will be used. diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 854bc8344b..8327df0b19 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -330,7 +330,8 @@ Benchmark* Benchmark::Args(const std::vector& args) { return this; } -Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) { +Benchmark* Benchmark::Apply( + const std::function& custom_arguments) { custom_arguments(this); return this; } From 188e8278990a9069ffc84441cb5a024fd0bede37 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 20 Nov 2025 21:32:14 -0500 Subject: [PATCH 424/561] Add missing type_traits include to benchmark_register.h (#2076) The file uses std::is_signed, which is in . Without this, this file won't build after https://llvm.org/PR168334 --- src/benchmark_register.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/benchmark_register.h b/src/benchmark_register.h index be50265f72..e0ace51ef0 100644 --- a/src/benchmark_register.h +++ b/src/benchmark_register.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "check.h" From 6f0461a3ce0b529f7f365d20f49dda613b769592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:44:24 +0000 Subject: [PATCH 425/561] Bump lukka/get-cmake from 4.1.2 to 4.2.0 (#2075) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.1.2 to 4.2.0. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/628dd514bed37cb0a609e84a6186cbbaa2fc0140...bb2faa721a800324b726fec00f7c1ff7641964d1) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 0599ac43c1..3807a4da5d 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - - uses: lukka/get-cmake@628dd514bed37cb0a609e84a6186cbbaa2fc0140 # latest + - uses: lukka/get-cmake@bb2faa721a800324b726fec00f7c1ff7641964d1 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 58cef026ee..99efe8a0cb 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - - uses: lukka/get-cmake@628dd514bed37cb0a609e84a6186cbbaa2fc0140 # latest + - uses: lukka/get-cmake@bb2faa721a800324b726fec00f7c1ff7641964d1 # latest - name: configure cmake run: > From c3f86578bb2081b52cee9d51615912ca4aa52fe4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:58:07 +0000 Subject: [PATCH 426/561] Bump actions/checkout from 5.0.1 to 6.0.0 (#2074) Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.1 to 6.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/93cb6efe18208431cddfb8368fd83d5badbf9bfd...1af3b93b6815bc44a9784bd300feb67ff0d1eeb3) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 268b1c2702..7b82e26bd0 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: mount bazel cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 3807a4da5d..282803c9df 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,7 +19,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: lukka/get-cmake@bb2faa721a800324b726fec00f7c1ff7641964d1 # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index dbd45cb8ea..ef95c3740e 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 99efe8a0cb..bf623b66e9 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,7 +30,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -77,7 +77,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: lukka/get-cmake@bb2faa721a800324b726fec00f7c1ff7641964d1 # latest @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 20e12031ce..0d5d663657 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index 8aeab2423c..9ebb36853f 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index fa02d6f21e..75990be9b3 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index f6e591f5a7..c93678f314 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run analysis uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 4dd21ecb16..50e8cb25cf 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 659bc9bce1..e85aab5627 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: configure msan env if: matrix.sanitizer == 'msan' diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index d1f00e38e5..df455d40e6 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 9756557560..74efd0a656 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - name: Install Python 3.12 @@ -38,7 +38,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 From 31a110a27821abc4b7c0d1ccfda94b33f87b9208 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 09:44:57 +0000 Subject: [PATCH 427/561] Bump actions/setup-python from 6.0.0 to 6.1.0 (#2079) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.0.0 to 6.1.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/e797f83bcb11b83ae66e0230d6156d7c80228e7c...83679a892e2d95755f2dac6acb0bfd1e9ac5d548) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index df455d40e6..9bdd862220 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -27,7 +27,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: ${{ matrix.python-version }} - name: Install GBM Python bindings on ${{ matrix.os }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 74efd0a656..2a143e6c58 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -19,7 +19,7 @@ jobs: with: fetch-depth: 0 - name: Install Python 3.12 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: "3.12" - run: python -m pip install build @@ -42,7 +42,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 name: Install Python 3.12 with: python-version: "3.12" From 2279f2acc8f2ca1bb51195a12966411bed31b26b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 09:59:52 +0000 Subject: [PATCH 428/561] Bump astral-sh/setup-uv from 7.1.3 to 7.1.4 (#2077) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.3 to 7.1.4. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/5a7eac68fb9809dea845d802897dc5c723910fa3...1e862dfacbd1d6d858c55d9b792c756523627244) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 50e8cb25cf..0b61e22f64 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@5a7eac68fb9809dea845d802897dc5c723910fa3 # v7.1.3 + uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 2a143e6c58..66bff91566 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@5a7eac68fb9809dea845d802897dc5c723910fa3 # v7.1.3 + uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0 From 6a8dee95ae1151142fe4be94482cdfd11b7111bd Mon Sep 17 00:00:00 2001 From: Hamza Date: Sat, 29 Nov 2025 00:33:03 +0000 Subject: [PATCH 429/561] Remove redundant feature checks on re-run of CMake config step (#2084) - On a config re-run, CMake will not check features again as it will read previously defined cache variables. - Logic was difficult to follow, so refactored `cxx_feature_check` for simplicity Fixes https://github.com/google/benchmark/issues/2078. --- CMakeLists.txt | 13 +++- cmake/CXXFeatureCheck.cmake | 114 +++++++++++++++++++++--------------- 2 files changed, 76 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 413c56af75..7bbaa2f67a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,10 +309,17 @@ if (BENCHMARK_USE_LIBCXX) endif(BENCHMARK_USE_LIBCXX) # C++ feature checks -# Determine the correct regular expression engine to use +# Determine the correct regular expression engine to use. First compatible engine found is used. cxx_feature_check(STD_REGEX) -cxx_feature_check(GNU_POSIX_REGEX) -cxx_feature_check(POSIX_REGEX) + +if(NOT HAVE_STD_REGEX) + cxx_feature_check(GNU_POSIX_REGEX) +endif() + +if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX) + cxx_feature_check(POSIX_REGEX) +endif() + if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX) message(FATAL_ERROR "Failed to determine the source files for the regular expression backend") endif() diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index ee5b7591e2..a163a6e094 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -10,22 +10,35 @@ # # include(CXXFeatureCheck) # cxx_feature_check(STD_REGEX) -# Requires CMake 2.8.12+ +# Requires CMake 3.13+ if(__cxx_feature_check) return() endif() set(__cxx_feature_check INCLUDED) -option(CXXFEATURECHECK_DEBUG OFF) +option(CXXFEATURECHECK_DEBUG OFF "Enable debug messages for CXX feature checks") -function(cxx_feature_check FILE) - string(TOLOWER ${FILE} FILE) - string(TOUPPER ${FILE} VAR) - string(TOUPPER "HAVE_${VAR}" FEATURE) - if (DEFINED HAVE_${VAR}) - set(HAVE_${VAR} 1 PARENT_SCOPE) - add_definitions(-DHAVE_${VAR}) +function(cxx_feature_check_print log) + if(CXXFEATURECHECK_DEBUG) + message(STATUS "${log}") + endif() +endfunction() + +function(cxx_feature_check FEATURE) + string(TOLOWER ${FEATURE} FILE) + string(TOUPPER HAVE_${FEATURE} VAR) + + # Check if the variable is already defined to a true or false for a quick return. + # This allows users to predefine the variable to skip the check. + # Or, if the variable is already defined by a previous check, we skip the costly check. + if (DEFINED ${VAR}) + if (${VAR}) + cxx_feature_check_print("Feature ${FEATURE} already enabled.") + add_compile_definitions(${VAR}) + else() + cxx_feature_check_print("Feature ${FEATURE} already disabled.") + endif() return() endif() @@ -35,48 +48,53 @@ function(cxx_feature_check FILE) list(APPEND FEATURE_CHECK_CMAKE_FLAGS ${ARGV1}) endif() - if (NOT DEFINED COMPILE_${FEATURE}) - if(CMAKE_CROSSCOMPILING) - message(STATUS "Cross-compiling to test ${FEATURE}") - try_compile(COMPILE_${FEATURE} - ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON - CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} - LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} - OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) - if(COMPILE_${FEATURE}) - message(WARNING - "If you see build failures due to cross compilation, try setting HAVE_${VAR} to 0") - set(RUN_${FEATURE} 0 CACHE INTERNAL "") - else() - set(RUN_${FEATURE} 1 CACHE INTERNAL "") - endif() - else() - message(STATUS "Compiling and running to test ${FEATURE}") - try_run(RUN_${FEATURE} COMPILE_${FEATURE} - ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON - CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} - LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} - COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) + if(CMAKE_CROSSCOMPILING) + cxx_feature_check_print("Cross-compiling to test ${FEATURE}") + try_compile( + COMPILE_STATUS + ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CMAKE_FLAGS "${FEATURE_CHECK_CMAKE_FLAGS}" + LINK_LIBRARIES "${BENCHMARK_CXX_LIBRARIES}" + OUTPUT_VARIABLE COMPILE_OUTPUT_VAR + ) + if(COMPILE_STATUS) + set(RUN_STATUS 0) + message(WARNING + "If you see build failures due to cross compilation, try setting ${VAR} to 0") endif() + else() + cxx_feature_check_print("Compiling and running to test ${FEATURE}") + try_run( + RUN_STATUS + COMPILE_STATUS + ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CMAKE_FLAGS "${FEATURE_CHECK_CMAKE_FLAGS}" + LINK_LIBRARIES "${BENCHMARK_CXX_LIBRARIES}" + COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE RUN_OUTPUT + ) endif() - if(COMPILE_${FEATURE}) - if(DEFINED RUN_${FEATURE} AND RUN_${FEATURE} EQUAL 0) - message(STATUS "Performing Test ${FEATURE} -- success") - set(HAVE_${VAR} 1 PARENT_SCOPE) - add_definitions(-DHAVE_${VAR}) - else() - message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run") - endif() + if(COMPILE_STATUS AND RUN_STATUS EQUAL 0) + message(STATUS "Performing Test ${FEATURE} -- success") + set(${VAR} TRUE CACHE BOOL "" FORCE) + add_compile_definitions(${VAR}) + return() + endif() + + set(${VAR} FALSE CACHE BOOL "" FORCE) + message(STATUS "Performing Test ${FEATURE} -- failed") + + if(NOT COMPILE_STATUS) + cxx_feature_check_print("Compile Output: ${COMPILE_OUTPUT}") else() - if(CXXFEATURECHECK_DEBUG) - message(STATUS "Performing Test ${FEATURE} -- failed to compile: ${COMPILE_OUTPUT_VAR}") - else() - message(STATUS "Performing Test ${FEATURE} -- failed to compile") - endif() + cxx_feature_check_print("Run Output: ${RUN_OUTPUT}") endif() + endfunction() From 009f05c24233ed5c8e3edc38a4ed927e2112358e Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 8 Dec 2025 10:04:32 -0500 Subject: [PATCH 430/561] Make the build work with -Wformat=2 (#2088) * Make the build work with -Wformat=2 The -Wformat=2 macro requires every format string either be a string literal, or a parameter that was tagged with the format attribute. The upshot is that it expects every printf function to be marked, or you get warnings like this: src/console_reporter.cc:104:23: error: format string is not a string literal [-Werror,-Wformat-nonliteral] 104 | out << FormatString(fmt, args); | ^~~ Marking such things is generally worthwhile since it turns on error-checking within the library, so fill in the missing ones. Tested with: bazelisk build --copt=-Werror --copt=-Wformat=2 :all * Add -Wformat=2 to catch regressions --- BUILD.bazel | 1 + CMakeLists.txt | 1 + src/colorprint.h | 12 ++---------- src/console_reporter.cc | 1 + src/internal_macros.h | 10 ++++++++++ src/string_util.cc | 1 + 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 178052c22c..993b261204 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -12,6 +12,7 @@ COPTS = [ "-Wshadow", # "-Wshorten-64-to-32", "-Wfloat-equal", + "-Wformat=2", "-fstrict-aliasing", ## assert() are used a lot in tests upstream, which may be optimised out leading to ## unused-variable warning. diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bbaa2f67a..7e50eec91e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,7 @@ else() add_cxx_compiler_flag(-Wfloat-equal) add_cxx_compiler_flag(-Wold-style-cast) add_cxx_compiler_flag(-Wconversion) + add_cxx_compiler_flag(-Wformat=2) if(BENCHMARK_ENABLE_WERROR) add_cxx_compiler_flag(-Werror) endif() diff --git a/src/colorprint.h b/src/colorprint.h index 477a030fd2..469045c5f5 100644 --- a/src/colorprint.h +++ b/src/colorprint.h @@ -5,6 +5,8 @@ #include #include +#include "internal_macros.h" + namespace benchmark { enum LogColor { COLOR_DEFAULT, @@ -17,16 +19,6 @@ enum LogColor { COLOR_WHITE }; -#if defined(__GNUC__) || defined(__clang__) -#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \ - __attribute__((format(printf, format_arg, first_idx))) -#elif defined(__MINGW32__) -#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \ - __attribute__((format(__MINGW_PRINTF_FORMAT, format_arg, first_idx))) -#else -#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) -#endif - PRINTF_FORMAT_STRING_FUNC(1, 0) std::string FormatString(const char* msg, va_list args); PRINTF_FORMAT_STRING_FUNC(1, 2) std::string FormatString(const char* msg, ...); diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 0bb9f27fbf..6db6788f94 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -97,6 +97,7 @@ void ConsoleReporter::ReportRuns(const std::vector& reports) { } } +PRINTF_FORMAT_STRING_FUNC(3, 4) static void IgnoreColorPrint(std::ostream& out, LogColor /*unused*/, const char* fmt, ...) { va_list args; diff --git a/src/internal_macros.h b/src/internal_macros.h index f4894ba8e6..22e3e21753 100644 --- a/src/internal_macros.h +++ b/src/internal_macros.h @@ -106,6 +106,16 @@ #define BENCHMARK_MAYBE_UNUSED #endif +#if defined(__GNUC__) || defined(__clang__) +#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \ + __attribute__((format(printf, format_arg, first_idx))) +#elif defined(__MINGW32__) +#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \ + __attribute__((format(__MINGW_PRINTF_FORMAT, format_arg, first_idx))) +#else +#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) +#endif + // clang-format on #endif // BENCHMARK_INTERNAL_MACROS_H_ diff --git a/src/string_util.cc b/src/string_util.cc index 1ba39dd088..9c5df3ba25 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -112,6 +112,7 @@ std::string ToBinaryStringFullySpecified(double value, int precision, return mantissa + ExponentToPrefix(exponent, one_k == Counter::kIs1024); } +PRINTF_FORMAT_STRING_FUNC(1, 0) std::string StrFormatImp(const char* msg, va_list args) { // we might need a second shot at this, so pre-emptivly make a copy va_list args_cp; From 1b150e2fb0c4b14b7f701f97b3b2f3c1e70c74b1 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 8 Dec 2025 21:59:07 +0300 Subject: [PATCH 431/561] Add tests for user counters w/ threads (#2089) --- test/CMakeLists.txt | 3 + test/user_counters_threads_test.cc | 615 +++++++++++++++++++++++++++++ 2 files changed, 618 insertions(+) create mode 100644 test/user_counters_threads_test.cc diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8c04ec3885..8a1a1a968f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -186,6 +186,9 @@ benchmark_add_test(NAME templated_fixture_method_test COMMAND templated_fixture_ compile_output_test(user_counters_test) benchmark_add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s) +compile_output_test(user_counters_threads_test) +benchmark_add_test(NAME user_counters_threads_test COMMAND user_counters_threads_test --benchmark_min_time=0.01s) + compile_output_test(perf_counters_test) benchmark_add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,INSTRUCTIONS) diff --git a/test/user_counters_threads_test.cc b/test/user_counters_threads_test.cc new file mode 100644 index 0000000000..027773e87c --- /dev/null +++ b/test/user_counters_threads_test.cc @@ -0,0 +1,615 @@ + +#undef NDEBUG + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// ========================================================================= // +// ---------------------- Testing Prologue Output -------------------------- // +// ========================================================================= // + +// clang-format off + +ADD_CASES(TC_ConsoleOut, + {{"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations UserCounters...$", MR_Next}, + {"^[-]+$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"%csv_header,\"bar\",\"foo\""}}); + +// clang-format on + +// ========================================================================= // +// ------------------------- Simple Counters Output ------------------------ // +// ========================================================================= // + +namespace { +void BM_Counters_Simple(benchmark::State& state) { + for (auto _ : state) { + } + state.counters["foo"] = 1; + state.counters["bar"] = 2 * static_cast(state.iterations()); +} +BENCHMARK(BM_Counters_Simple)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Simple/threads:%int %console_report " + "bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Simple/threads:%int\",$"}, + {"\"family_index\": 0,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_Simple/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES( + TC_CSVOut, + {{"^\"BM_Counters_Simple/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSimple(Results const& e) { + double its = e.NumIterations(); + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1 * e.NumThreads()); + // check that the value of bar is within 0.1% of the expected value + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Simple/threads:%int", &CheckSimple); +} // end namespace + +// ========================================================================= // +// --------------------- Counters+Items+Bytes/s Output --------------------- // +// ========================================================================= // + +namespace { +void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); + benchmark::DoNotOptimize(iterations); + } + state.counters["foo"] = 1; + state.SetBytesProcessed(364); + state.SetItemsProcessed(150); +} +BENCHMARK(BM_Counters_WithBytesAndItemsPSec)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Counters_WithBytesAndItemsPSec/threads:%int %console_report " + "bytes_per_second=%hrfloat/s " + "foo=%hrfloat items_per_second=%hrfloat/s$"}}); +ADD_CASES( + TC_JSONOut, + {{"\"name\": \"BM_Counters_WithBytesAndItemsPSec/threads:%int\",$"}, + {"\"family_index\": 1,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_WithBytesAndItemsPSec/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bytes_per_second\": %float,$", MR_Next}, + {"\"foo\": %float,$", MR_Next}, + {"\"items_per_second\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_WithBytesAndItemsPSec/threads:%int\"," + "%csv_bytes_items_report,,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckBytesAndItemsPSec(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1 * e.NumThreads()); + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_RESULT_VALUE(e, "bytes_per_second", EQ, + (364. * e.NumThreads()) / t, 0.001); + CHECK_FLOAT_RESULT_VALUE(e, "items_per_second", EQ, + (150. * e.NumThreads()) / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec/threads:%int", + &CheckBytesAndItemsPSec); +} // end namespace + +// ========================================================================= // +// ------------------------- Rate Counters Output -------------------------- // +// ========================================================================= // +namespace { +void BM_Counters_Rate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); + benchmark::DoNotOptimize(iterations); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kIsRate}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kIsRate}; +} +BENCHMARK(BM_Counters_Rate)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Rate/threads:%int %console_report " + "bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Rate/threads:%int\",$"}, + {"\"family_index\": 2,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_Rate/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{"^\"BM_Counters_Rate/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckRate(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, (1. * e.NumThreads()) / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, (2. * e.NumThreads()) / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Rate/threads:%int", &CheckRate); +} // end namespace + +// ========================================================================= // +// ----------------------- Inverted Counters Output ------------------------ // +// ========================================================================= // + +namespace { +void BM_Invert(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); + benchmark::DoNotOptimize(iterations); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{0.0001, bm::Counter::kInvert}; + state.counters["bar"] = bm::Counter{10000, bm::Counter::kInvert}; +} +BENCHMARK(BM_Invert)->ThreadRange(1, 8); +ADD_CASES( + TC_ConsoleOut, + {{"^BM_Invert/threads:%int %console_report bar=%hrfloatu foo=%hrfloatk$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Invert/threads:%int\",$"}, + {"\"family_index\": 3,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Invert/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{"^\"BM_Invert/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckInvert(Results const& e) { + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / (0.0001 * e.NumThreads()), + 0.0001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 1. / (10000 * e.NumThreads()), + 0.0001); +} +CHECK_BENCHMARK_RESULTS("BM_Invert/threads:%int", &CheckInvert); +} // end namespace + +// ========================================================================= // +// --------------------- InvertedRate Counters Output ---------------------- // +// ========================================================================= // + +namespace { +void BM_Counters_InvertedRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); + benchmark::DoNotOptimize(iterations); + } + namespace bm = benchmark; + state.counters["foo"] = + bm::Counter{1, bm::Counter::kIsRate | bm::Counter::kInvert}; + state.counters["bar"] = + bm::Counter{8192, bm::Counter::kIsRate | bm::Counter::kInvert}; +} +BENCHMARK(BM_Counters_InvertedRate)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Counters_InvertedRate/threads:%int %console_report " + "bar=%hrfloats foo=%hrfloats$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_InvertedRate/threads:%int\",$"}, + {"\"family_index\": 4,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_InvertedRate/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_InvertedRate/" + "threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckInvertedRate(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, t / (e.NumThreads()), 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / (8192.0 * e.NumThreads()), 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_InvertedRate/threads:%int", + &CheckInvertedRate); +} // end namespace + +// ========================================================================= // +// ------------------------- Thread Counters Output ------------------------ // +// ========================================================================= // + +namespace { +void BM_Counters_Threads(benchmark::State& state) { + for (auto _ : state) { + } + state.counters["foo"] = 1; + state.counters["bar"] = 2; +} +BENCHMARK(BM_Counters_Threads)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Threads/threads:%int %console_report " + "bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Threads/threads:%int\",$"}, + {"\"family_index\": 5,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_Threads/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES( + TC_CSVOut, + {{"^\"BM_Counters_Threads/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckThreads(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "foo", EQ, e.NumThreads()); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2 * e.NumThreads()); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Threads/threads:%int", &CheckThreads); +} // end namespace + +// ========================================================================= // +// ---------------------- ThreadAvg Counters Output ------------------------ // +// ========================================================================= // + +namespace { +void BM_Counters_AvgThreads(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreads}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreads}; +} +BENCHMARK(BM_Counters_AvgThreads)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreads/threads:%int " + "%console_report bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_AvgThreads/threads:%int\",$"}, + {"\"family_index\": 6,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_AvgThreads/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES( + TC_CSVOut, + {{"^\"BM_Counters_AvgThreads/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgThreads(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int", + &CheckAvgThreads); +} // end namespace + +// ========================================================================= // +// ---------------------- ThreadAvg Counters Output ------------------------ // +// ========================================================================= // + +namespace { +void BM_Counters_AvgThreadsRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); + benchmark::DoNotOptimize(iterations); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreadsRate}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreadsRate}; +} +BENCHMARK(BM_Counters_AvgThreadsRate)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreadsRate/threads:%int " + "%console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$"}, + {"\"family_index\": 7,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/" + "threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgThreadsRate(Results const& e) { + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / e.DurationCPUTime(), 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / e.DurationCPUTime(), 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int", + &CheckAvgThreadsRate); +} // end namespace + +// ========================================================================= // +// ------------------- IterationInvariant Counters Output ------------------ // +// ========================================================================= // + +namespace { +void BM_Counters_IterationInvariant(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kIsIterationInvariant}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kIsIterationInvariant}; +} +BENCHMARK(BM_Counters_IterationInvariant)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Counters_IterationInvariant/threads:%int %console_report " + "bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_IterationInvariant/threads:%int\",$"}, + {"\"family_index\": 8,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_IterationInvariant/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_IterationInvariant/" + "threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckIterationInvariant(Results const& e) { + double its = e.NumIterations(); + // check that the values are within 0.1% of the expected value + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * e.NumThreads(), 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its * e.NumThreads(), 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant/threads:%int", + &CheckIterationInvariant); +} // end namespace + +// ========================================================================= // +// ----------------- IterationInvariantRate Counters Output ---------------- // +// ========================================================================= // + +namespace { +void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); + benchmark::DoNotOptimize(iterations); + } + namespace bm = benchmark; + state.counters["foo"] = + bm::Counter{1, bm::Counter::kIsIterationInvariantRate}; + state.counters["bar"] = + bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kIsIterationInvariant}; +} +BENCHMARK(BM_Counters_kIsIterationInvariantRate)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Counters_kIsIterationInvariantRate/threads:%int " + "%console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES( + TC_JSONOut, + {{"\"name\": \"BM_Counters_kIsIterationInvariantRate/threads:%int\",$"}, + {"\"family_index\": 9,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_kIsIterationInvariantRate/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES( + TC_CSVOut, + {{"^\"BM_Counters_kIsIterationInvariantRate/threads:%int\",%csv_report," + "%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckIsIterationInvariantRate(Results const& e) { + double its = e.NumIterations(); + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * 1. * e.NumThreads() / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, its * 2. * e.NumThreads() / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_kIsIterationInvariantRate/threads:%int", + &CheckIsIterationInvariantRate); +} // end namespace + +// ========================================================================= // +// --------------------- AvgIterations Counters Output --------------------- // +// ========================================================================= // + +namespace { +void BM_Counters_AvgIterations(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterations}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgIterations}; +} +BENCHMARK(BM_Counters_AvgIterations)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Counters_AvgIterations/threads:%int %console_report " + "bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_AvgIterations/threads:%int\",$"}, + {"\"family_index\": 10,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_AvgIterations/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgIterations/" + "threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgIterations(Results const& e) { + double its = e.NumIterations(); + // check that the values are within 0.1% of the expected value + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. * e.NumThreads() / its, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * e.NumThreads() / its, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations/threads:%int", + &CheckAvgIterations); +} // end namespace + +// ========================================================================= // +// ------------------- AvgIterationsRate Counters Output ------------------- // +// ========================================================================= // + +namespace { +void BM_Counters_kAvgIterationsRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + auto iterations = static_cast(state.iterations()) * + static_cast(state.iterations()); + benchmark::DoNotOptimize(iterations); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterationsRate}; + state.counters["bar"] = + bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kAvgIterations}; +} +BENCHMARK(BM_Counters_kAvgIterationsRate)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_kAvgIterationsRate/threads:%int " + "%console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_kAvgIterationsRate/threads:%int\",$"}, + {"\"family_index\": 11,$", MR_Next}, + {"\"per_family_instance_index\": 0,$", MR_Next}, + {"\"run_name\": \"BM_Counters_kAvgIterationsRate/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": %int,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{"^\"BM_Counters_kAvgIterationsRate/threads:%int\",%csv_report," + "%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgIterationsRate(Results const& e) { + double its = e.NumIterations(); + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. * e.NumThreads() / its / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * e.NumThreads() / its / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_kAvgIterationsRate/threads:%int", + &CheckAvgIterationsRate); +} // end namespace + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); +} From ade834a6d5c3febf3d876adad0072e956b779610 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:22:19 +0000 Subject: [PATCH 432/561] Bump lukka/get-cmake from 4.2.0 to 4.2.1 (#2091) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/bb2faa721a800324b726fec00f7c1ff7641964d1...9e07ecdcee1b12e5037e42f410b67f03e2f626e1) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 282803c9df..e1ae56d53f 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - uses: lukka/get-cmake@bb2faa721a800324b726fec00f7c1ff7641964d1 # latest + - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bf623b66e9..72212125f7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - uses: lukka/get-cmake@bb2faa721a800324b726fec00f7c1ff7641964d1 # latest + - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest - name: configure cmake run: > From 2f550a37bdf168068016dbf14586dc36cc678b12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:36:47 +0000 Subject: [PATCH 433/561] Bump actions/checkout from 6.0.0 to 6.0.1 (#2086) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/1af3b93b6815bc44a9784bd300feb67ff0d1eeb3...8e8c483db84b4bee98b60c0593521ed34d9990e8) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 7b82e26bd0..ad66017f28 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: mount bazel cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index e1ae56d53f..c9d6e049ab 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,7 +19,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index ef95c3740e..df2ff34643 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 72212125f7..c6074b6db2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,7 +30,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -77,7 +77,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 0d5d663657..c9f0315f60 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index 9ebb36853f..1c92cfc1f6 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 75990be9b3..075a385d32 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index c93678f314..db742fb0f7 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Run analysis uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 0b61e22f64..66015d9296 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index e85aab5627..d44822f1c5 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: configure msan env if: matrix.sanitizer == 'msan' diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 9bdd862220..191239c6a7 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 66bff91566..880244d984 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 - name: Install Python 3.12 @@ -38,7 +38,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 From 63f16af14b80aa67d89a0b741e67419a55fce408 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:42:53 +0000 Subject: [PATCH 434/561] Bump astral-sh/setup-uv from 7.1.4 to 7.1.5 (#2090) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.4 to 7.1.5. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/1e862dfacbd1d6d858c55d9b792c756523627244...ed21f2f24f8dd64503750218de024bcf64c7250a) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 66015d9296..4e3c3105dc 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 + uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 880244d984..c3264626f6 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 + uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0 From 3e7dac665b52d1901c37f3efbc173aabf7a8f3cb Mon Sep 17 00:00:00 2001 From: Frank Rosner <3427394+FRosner@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:38:32 +0100 Subject: [PATCH 435/561] #2080: Fix rate and thread rate counter aggregates (#2081) * Update counter.cc * User counters: normalize time by thread count Fixes https://github.com/google/benchmark/issues/2080 * docs --------- Co-authored-by: Roman Lebedev --- docs/user_guide.md | 8 ++++---- src/benchmark_runner.cc | 7 ++++++- test/user_counters_tabular_test.cc | 2 +- test/user_counters_test.cc | 6 ++++-- test/user_counters_threads_test.cc | 21 ++++++++++++++------- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index ae8e1251bd..72fb6824a5 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -749,10 +749,6 @@ and `Counter` values. The latter is a `double`-like class, via an implicit conversion to `double&`. Thus you can use all of the standard arithmetic assignment operators (`=,+=,-=,*=,/=`) to change the value of each counter. -In multithreaded benchmarks, each counter is set on the calling thread only. -When the benchmark finishes, the counters from each thread will be summed; -the resulting sum is the value which will be shown for the benchmark. - The `Counter` constructor accepts three parameters: the value as a `double` ; a bit flag which allows you to show counters as rates, and/or as per-thread iteration, and/or as per-thread averages, and/or iteration invariants, @@ -797,6 +793,10 @@ You can use `insert()` with `std::initializer_list`: ``` +In multithreaded benchmarks, each counter is set on the calling thread only. +When the benchmark finishes, the counters from each thread will be summed. +Counters that are configured with `kIsRate`, will report the average rate across all threads, while `kAvgThreadsRate` counters will report the average rate per thread. + ### Counter Reporting When using the console reporter, by default, user counters are printed at diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 3cfa8a4e1e..d8a2357adc 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -123,7 +123,12 @@ BenchmarkReporter::Run CreateRunReport( : 0; } - internal::Finish(&report.counters, results.iterations, seconds, + // The CPU time is the total time taken by all thread. If we used that as + // the denominator, we'd be calculating the rate per thread here. This is + // why we have to divide the total cpu_time by the number of threads for + // global counters to get a global rate. + const double thread_seconds = seconds / b.threads(); + internal::Finish(&report.counters, results.iterations, thread_seconds, b.threads()); } return report; diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index d53ffdc48b..7db0e20822 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -418,7 +418,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_CounterRates_Tabular/threads:%int\",%csv_report," // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() void CheckTabularRate(Results const& e) { - double t = e.DurationCPUTime(); + double t = e.DurationCPUTime() / e.NumThreads(); CHECK_FLOAT_COUNTER_VALUE(e, "Foo", EQ, 1. / t, 0.001); CHECK_FLOAT_COUNTER_VALUE(e, "Bar", EQ, 2. / t, 0.001); CHECK_FLOAT_COUNTER_VALUE(e, "Baz", EQ, 4. / t, 0.001); diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index c55ad98bf2..a8af0877cc 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -381,8 +381,10 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/" // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() void CheckAvgThreadsRate(Results const& e) { - CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / e.DurationCPUTime(), 0.001); - CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / e.DurationCPUTime(), 0.001); + // this (and not real time) is the time used + double t = e.DurationCPUTime() / e.NumThreads(); + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001); } CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int", &CheckAvgThreadsRate); diff --git a/test/user_counters_threads_test.cc b/test/user_counters_threads_test.cc index 027773e87c..e2e5ade460 100644 --- a/test/user_counters_threads_test.cc +++ b/test/user_counters_threads_test.cc @@ -107,7 +107,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_WithBytesAndItemsPSec/threads:%int\"," // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() void CheckBytesAndItemsPSec(Results const& e) { - double t = e.DurationCPUTime(); // this (and not real time) is the time used + // this (and not real time) is the time used + double t = e.DurationCPUTime() / e.NumThreads(); CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1 * e.NumThreads()); // check that the values are within 0.1% of the expected values CHECK_FLOAT_RESULT_VALUE(e, "bytes_per_second", EQ, @@ -158,7 +159,8 @@ ADD_CASES(TC_CSVOut, // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() void CheckRate(Results const& e) { - double t = e.DurationCPUTime(); // this (and not real time) is the time used + // this (and not real time) is the time used + double t = e.DurationCPUTime() / e.NumThreads(); // check that the values are within 0.1% of the expected values CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, (1. * e.NumThreads()) / t, 0.001); CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, (2. * e.NumThreads()) / t, 0.001); @@ -258,7 +260,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_InvertedRate/" // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() void CheckInvertedRate(Results const& e) { - double t = e.DurationCPUTime(); // this (and not real time) is the time used + // this (and not real time) is the time used + double t = e.DurationCPUTime() / e.NumThreads(); // check that the values are within 0.1% of the expected values CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, t / (e.NumThreads()), 0.001); CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / (8192.0 * e.NumThreads()), 0.001); @@ -394,8 +397,10 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/" // VS2013 does not allow this function to be passed as a lambda argument // to CHECK_BENCHMARK_RESULTS() void CheckAvgThreadsRate(Results const& e) { - CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / e.DurationCPUTime(), 0.001); - CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / e.DurationCPUTime(), 0.001); + // this (and not real time) is the time used + double t = e.DurationCPUTime() / e.NumThreads(); + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001); } CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int", &CheckAvgThreadsRate); @@ -496,7 +501,8 @@ ADD_CASES( // to CHECK_BENCHMARK_RESULTS() void CheckIsIterationInvariantRate(Results const& e) { double its = e.NumIterations(); - double t = e.DurationCPUTime(); // this (and not real time) is the time used + // this (and not real time) is the time used + double t = e.DurationCPUTime() / e.NumThreads(); // check that the values are within 0.1% of the expected values CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * 1. * e.NumThreads() / t, 0.001); CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, its * 2. * e.NumThreads() / t, 0.001); @@ -596,7 +602,8 @@ ADD_CASES(TC_CSVOut, // to CHECK_BENCHMARK_RESULTS() void CheckAvgIterationsRate(Results const& e) { double its = e.NumIterations(); - double t = e.DurationCPUTime(); // this (and not real time) is the time used + // this (and not real time) is the time used + double t = e.DurationCPUTime() / e.NumThreads(); // check that the values are within 0.1% of the expected values CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. * e.NumThreads() / its / t, 0.001); CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * e.NumThreads() / its / t, 0.001); From 8b940fbc72f7399d79c8382655b74719ce1df650 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 11:22:58 +0000 Subject: [PATCH 436/561] Bump actions/download-artifact from 6.0.0 to 7.0.0 (#2094) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/018cc2cf5baa6db3ef3c5f8a56943fffe632ef53...37930b1c2abaa49bbe596cd826c3c89aef350131) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c3264626f6..0adeb8717a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -76,7 +76,7 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: path: dist pattern: dist-* From 4caa0f028c34c31972b0ab2b3236fdf4199c3ad3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 11:40:29 +0000 Subject: [PATCH 437/561] Bump actions/upload-artifact from 5.0.0 to 6.0.0 (#2093) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/330a01c490aca151604b8cf639adc76d48f6c5d4...b7c566a772e6b6bfb58ed0dc250532a479d7789f) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 0adeb8717a..c1b544f9fe 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -25,7 +25,7 @@ jobs: - run: python -m pip install build - name: Build sdist run: python -m build --sdist - - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: dist-sdist path: dist/*.tar.gz @@ -64,7 +64,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-15-intel' && 10.14 || 11.0 }} - name: Upload Google Benchmark ${{ matrix.os }} wheels - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: dist-${{ matrix.os }} path: wheelhouse/*.whl From bc71af254c5b9ba90e77727b2114739c53c81f66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 12:06:28 +0000 Subject: [PATCH 438/561] Bump actions/cache from 4.3.0 to 5.0.1 (#2092) Bumps [actions/cache](https://github.com/actions/cache) from 4.3.0 to 5.0.1. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/0057852bfaa89a56745cba8c7296529d2fc39830...9255dc7a253b0ccc959486e2bca901246202afeb) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index ad66017f28..bf181ba7ef 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: mount bazel cache - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 env: cache-name: bazel-cache with: From 5411a3cd207a49f3a99f8a6a0454e8e87efc0118 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:28:43 +0000 Subject: [PATCH 439/561] Bump msys2/setup-msys2 from 2.29.0 to 2.30.0 (#2096) Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.29.0 to 2.30.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/fb197b72ce45fb24f17bf3f807a388985654d1f2...4f806de0a5a7294ffabaff804b38a9b435a73bda) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.30.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c6074b6db2..90215c5abf 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -117,7 +117,7 @@ jobs: steps: - name: setup msys2 - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 + uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0 with: cache: false msystem: ${{ matrix.msys2.msystem }} From 04ccbd86038796c319ea19987457e651a24f6b44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:35:12 +0000 Subject: [PATCH 440/561] Bump astral-sh/setup-uv from 7.1.5 to 7.1.6 (#2095) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.5 to 7.1.6. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/ed21f2f24f8dd64503750218de024bcf64c7250a...681c641aba71e4a1c380be3ab5e12ad51f415867) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 4e3c3105dc..52234d820a 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 + uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c1b544f9fe..d3c265e629 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 + uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0 From 4a76220087697a1627d23784b248816fab1cb90b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Dec 2025 23:44:40 +0300 Subject: [PATCH 441/561] Bump egor-tensin/setup-clang from 1.4 to 2.1 (#2098) Bumps [egor-tensin/setup-clang](https://github.com/egor-tensin/setup-clang) from 1.4 to 2.1. - [Release notes](https://github.com/egor-tensin/setup-clang/releases) - [Commits](https://github.com/egor-tensin/setup-clang/compare/ef434b41eb33a70396fb336b1bae39c76d740c3d...471a6f8ef1d449dba8e1a51780e7f943572a3f99) --- updated-dependencies: - dependency-name: egor-tensin/setup-clang dependency-version: '2.1' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sanitizer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index d44822f1c5..6e9404f090 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -52,7 +52,7 @@ jobs: echo "ASAN_OPTIONS=alloc_dealloc_mismatch=0" >> $GITHUB_ENV - name: setup clang - uses: egor-tensin/setup-clang@ef434b41eb33a70396fb336b1bae39c76d740c3d # v1.4 + uses: egor-tensin/setup-clang@471a6f8ef1d449dba8e1a51780e7f943572a3f99 # v2.1 with: version: latest platform: x64 From 493123710daa07143982a82a156ad7ff489aa3d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 00:29:35 +0300 Subject: [PATCH 442/561] Bump numpy from 2.3.5 to 2.4.0 in /tools (#2097) Bumps [numpy](https://github.com/numpy/numpy) from 2.3.5 to 2.4.0. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.3.5...v2.4.0) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Roman Lebedev --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 419e2defb5..19d5cea2cd 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.3.5 +numpy == 2.4.0 scipy == 1.16.3 From 571265d36b85b0e0d02f5dad4d22aa797e95c533 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 01:05:40 +0300 Subject: [PATCH 443/561] Bump astral-sh/setup-uv from 7.1.6 to 7.2.0 (#2099) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.6 to 7.2.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/681c641aba71e4a1c380be3ab5e12ad51f415867...61cb8a9741eeb8a550a1b8544337180c0fc8476b) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Roman Lebedev --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 52234d820a..f6300601d6 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 + uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d3c265e629..67c93eab3b 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 + uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0 From 27fc2bf44144860006b6a4b854dbc04b6e1e76e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 01:30:47 +0300 Subject: [PATCH 444/561] Bump pypa/cibuildwheel from 3.3.0 to 3.3.1 (#2100) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/63fd63b352a9a8bdcc24791c9dbee952ee9a8abc...298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Roman Lebedev --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 67c93eab3b..c0c8eab565 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0 + uses: pypa/cibuildwheel@298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e # v3.3.1 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From a6e0a72355d80222f0d7a18c38d1dfb21da0e95f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:09:47 +0000 Subject: [PATCH 445/561] Bump numpy from 2.4.0 to 2.4.1 in /tools (#2102) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.0...v2.4.1) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 19d5cea2cd..a69a5c8c39 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.4.0 +numpy == 2.4.1 scipy == 1.16.3 From 262afc90167b0eb468a7461221563dc749a4162a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:28:16 +0000 Subject: [PATCH 446/561] Bump scipy from 1.16.3 to 1.17.0 in /tools (#2103) Bumps [scipy](https://github.com/scipy/scipy) from 1.16.3 to 1.17.0. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.16.3...v1.17.0) --- updated-dependencies: - dependency-name: scipy dependency-version: 1.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index a69a5c8c39..12d5d9ce99 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ numpy == 2.4.1 -scipy == 1.16.3 +scipy == 1.17.0 From 90ebbdedf00411ee76506224dd286d6a3f9564d3 Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Wed, 14 Jan 2026 19:04:17 +0100 Subject: [PATCH 447/561] Make the Benchmark class public (#2101) Move ::benchmark::internal::Benchmark to ::benchmark::Benchmark. It's a bit odd that the documented way to pass arguments to a benchmark is with `benchmark::internal::Benchmark`. Make this public instead. https://github.com/google/benchmark/blob/v1.9.4/docs/user_guide.md#passing-arguments https://raw.githubusercontent.com/google/benchmark/refs/tags/v1.9.4/docs/user_guide.md#:~:text=void%20CustomArguments(benchmark%3A%3A-,internal%3A%3ABenchmark,-*%20b)%20%7B%0A%20%20for%20(int Keep ::benchmark::internal::Benchmark as a deprecated forwarding alias. Uses of Benchmark in the internal namespace need to explicitly use ::benchmark::Benchmark to avoid the deprecation warning. --- bindings/python/google_benchmark/benchmark.cc | 6 +- docs/user_guide.md | 2 +- include/benchmark/benchmark.h | 69 ++++++++++--------- src/benchmark_api_internal.cc | 3 +- src/benchmark_api_internal.h | 4 +- src/benchmark_register.cc | 42 ++++++----- src/benchmark_runner.cc | 3 +- ...benchmark_setup_teardown_cb_types_gtest.cc | 2 +- test/memory_results_gtest.cc | 2 +- test/options_test.cc | 2 +- test/register_benchmark_test.cc | 2 +- test/time_unit_gtest.cc | 2 +- 12 files changed, 78 insertions(+), 61 deletions(-) diff --git a/bindings/python/google_benchmark/benchmark.cc b/bindings/python/google_benchmark/benchmark.cc index 175d35160e..ccd7eb5a50 100644 --- a/bindings/python/google_benchmark/benchmark.cc +++ b/bindings/python/google_benchmark/benchmark.cc @@ -36,8 +36,8 @@ std::vector Initialize(const std::vector& argv) { return remaining_argv; } -benchmark::internal::Benchmark* RegisterBenchmark(const std::string& name, - nb::callable f) { +benchmark::Benchmark* RegisterBenchmark(const std::string& name, + nb::callable f) { return benchmark::RegisterBenchmark( name, [f](benchmark::State& state) { f(&state); }); } @@ -64,7 +64,7 @@ NB_MODULE(_benchmark, m) { .value("oLambda", BigO::oLambda) .export_values(); - using benchmark::internal::Benchmark; + using benchmark::Benchmark; nb::class_(m, "Benchmark") // For methods returning a pointer to the current object, reference // return policy is used to ask nanobind not to take ownership of the diff --git a/docs/user_guide.md b/docs/user_guide.md index 72fb6824a5..997737f63a 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -452,7 +452,7 @@ benchmark. The following example enumerates a dense range on one parameter, and a sparse range on the second. ```c++ -static void CustomArguments(benchmark::internal::Benchmark* b) { +static void CustomArguments(benchmark::Benchmark* b) { for (int i = 0; i <= 10; ++i) for (int j = 32; j <= 1024*1024; j *= 8) b->Args({i, j}); diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index b6153e490e..3b2015306b 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -103,7 +103,7 @@ BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}}); // arbitrary set of arguments to run the microbenchmark on. // The following example enumerates a dense range on // one parameter, and a sparse range on the second. -static void CustomArguments(benchmark::internal::Benchmark* b) { +static void CustomArguments(benchmark::Benchmark* b) { for (int i = 0; i <= 10; ++i) for (int j = 32; j <= 1024*1024; j *= 8) b->Args({i, j}); @@ -488,8 +488,9 @@ void RegisterProfilerManager(ProfilerManager* profiler_manager); BENCHMARK_EXPORT void AddCustomContext(std::string key, std::string value); -namespace internal { class Benchmark; + +namespace internal { class BenchmarkImp; class BenchmarkFamilies; @@ -1125,20 +1126,15 @@ struct ThreadRunnerBase { virtual void RunThreads(const std::function& fn) = 0; }; -namespace internal { - // Define alias of ThreadRunner factory function type using threadrunner_factory = std::function(int)>; -typedef void(Function)(State&); - // ------------------------------------------------------ -// Benchmark registration object. The BENCHMARK() macro expands -// into an internal::Benchmark* object. Various methods can -// be called on this object to change the properties of the benchmark. -// Each method returns "this" so that multiple method calls can -// chained into one expression. +// Benchmark registration object. The BENCHMARK() macro expands into a +// Benchmark* object. Various methods can be called on this object to +// change the properties of the benchmark. Each method returns "this" so +// that multiple method calls can chained into one expression. class BENCHMARK_EXPORT Benchmark { public: virtual ~Benchmark(); @@ -1352,11 +1348,11 @@ class BENCHMARK_EXPORT Benchmark { const char* GetArgName(int arg) const; private: - friend class BenchmarkFamilies; - friend class BenchmarkInstance; + friend class internal::BenchmarkFamilies; + friend class internal::BenchmarkInstance; std::string name_; - AggregationReportMode aggregation_report_mode_; + internal::AggregationReportMode aggregation_report_mode_; std::vector arg_names_; // Args for all benchmark runs std::vector> args_; // Args for all benchmark runs @@ -1373,7 +1369,7 @@ class BENCHMARK_EXPORT Benchmark { bool use_manual_time_; BigO complexity_; BigOFunc* complexity_lambda_; - std::vector statistics_; + std::vector statistics_; std::vector thread_counts_; callback_function setup_; @@ -1384,17 +1380,28 @@ class BENCHMARK_EXPORT Benchmark { BENCHMARK_DISALLOW_COPY_AND_ASSIGN(Benchmark); }; +namespace internal { + +// clang-format off +typedef BENCHMARK_DEPRECATED_MSG("Use ::benchmark::Benchmark instead") + ::benchmark::Benchmark Benchmark; +typedef BENCHMARK_DEPRECATED_MSG( + "Use ::benchmark::threadrunner_factory instead") + ::benchmark::threadrunner_factory threadrunner_factory; +// clang-format on + +typedef void(Function)(State&); + } // namespace internal // Create and register a benchmark with the specified 'name' that invokes // the specified functor 'fn'. // // RETURNS: A pointer to the registered benchmark. -internal::Benchmark* RegisterBenchmark(const std::string& name, - internal::Function* fn); +Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn); template -internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn); +Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn); // Remove all registered benchmarks. All pointers to previously registered // benchmarks are invalidated. @@ -1403,7 +1410,7 @@ BENCHMARK_EXPORT void ClearRegisteredBenchmarks(); namespace internal { // The class used to hold all Benchmarks created from static function. // (ie those created using the BENCHMARK(...) macros. -class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark { +class BENCHMARK_EXPORT FunctionBenchmark : public benchmark::Benchmark { public: FunctionBenchmark(const std::string& name, Function* func) : Benchmark(name), func_(func) {} @@ -1415,7 +1422,7 @@ class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark { }; template -class LambdaBenchmark : public Benchmark { +class LambdaBenchmark : public benchmark::Benchmark { public: void Run(State& st) override { lambda_(st); } @@ -1429,15 +1436,15 @@ class LambdaBenchmark : public Benchmark { }; } // namespace internal -inline internal::Benchmark* RegisterBenchmark(const std::string& name, - internal::Function* fn) { +inline Benchmark* RegisterBenchmark(const std::string& name, + internal::Function* fn) { return internal::RegisterBenchmarkInternal( ::benchmark::internal::make_unique(name, fn)); } template -internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { +Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { using BenchType = internal::LambdaBenchmark::type>; return internal::RegisterBenchmarkInternal( @@ -1446,16 +1453,16 @@ internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { } template -internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn, - Args&&... args) { +Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn, + Args&&... args) { return benchmark::RegisterBenchmark( name, [=](benchmark::State& st) { fn(st, args...); }); } // The base class for all fixture tests. -class Fixture : public internal::Benchmark { +class Fixture : public Benchmark { public: - Fixture() : internal::Benchmark("") {} + Fixture() : Benchmark("") {} void Run(State& st) override { this->SetUp(st); @@ -1498,10 +1505,10 @@ class Fixture : public internal::Benchmark { #define BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method) \ BaseClass##_##Method##_Benchmark -#define BENCHMARK_PRIVATE_DECLARE(n) \ - /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ - static ::benchmark::internal::Benchmark const* const BENCHMARK_PRIVATE_NAME( \ - n) BENCHMARK_UNUSED +#define BENCHMARK_PRIVATE_DECLARE(n) \ + /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ + static ::benchmark::Benchmark const* const BENCHMARK_PRIVATE_NAME(n) \ + BENCHMARK_UNUSED #define BENCHMARK(...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ diff --git a/src/benchmark_api_internal.cc b/src/benchmark_api_internal.cc index 60609d30cd..f9c4990ddf 100644 --- a/src/benchmark_api_internal.cc +++ b/src/benchmark_api_internal.cc @@ -7,7 +7,8 @@ namespace benchmark { namespace internal { -BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx, +BenchmarkInstance::BenchmarkInstance(benchmark::Benchmark* benchmark, + int family_idx, int per_family_instance_idx, const std::vector& args, int thread_count) diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h index efa0602173..5b48ea2fdf 100644 --- a/src/benchmark_api_internal.h +++ b/src/benchmark_api_internal.h @@ -17,7 +17,7 @@ namespace internal { // Information kept per benchmark we may want to run class BenchmarkInstance { public: - BenchmarkInstance(Benchmark* benchmark, int family_idx, + BenchmarkInstance(benchmark::Benchmark* benchmark, int family_idx, int per_family_instance_idx, const std::vector& args, int thread_count); @@ -52,7 +52,7 @@ class BenchmarkInstance { private: BenchmarkName name_; - Benchmark& benchmark_; + benchmark::Benchmark& benchmark_; const int family_index_; const int per_family_instance_index_; AggregationReportMode aggregation_report_mode_; diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 8327df0b19..65e1afced3 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -75,7 +75,7 @@ class BenchmarkFamilies { static BenchmarkFamilies* GetInstance(); // Registers a benchmark family and returns the index assigned to it. - size_t AddBenchmark(std::unique_ptr family); + size_t AddBenchmark(std::unique_ptr family); // Clear all registered benchmark families. void ClearBenchmarks(); @@ -89,7 +89,7 @@ class BenchmarkFamilies { private: BenchmarkFamilies() {} - std::vector> families_; + std::vector> families_; Mutex mutex_; }; @@ -98,7 +98,8 @@ BenchmarkFamilies* BenchmarkFamilies::GetInstance() { return &instance; } -size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr family) { +size_t BenchmarkFamilies::AddBenchmark( + std::unique_ptr family) { MutexLock l(mutex_); size_t index = families_.size(); families_.push_back(std::move(family)); @@ -135,7 +136,7 @@ bool BenchmarkFamilies::FindBenchmarks( int next_family_index = 0; MutexLock l(mutex_); - for (std::unique_ptr& family : families_) { + for (std::unique_ptr& family : families_) { int family_index = next_family_index; int per_family_instance_index = 0; @@ -191,8 +192,9 @@ bool BenchmarkFamilies::FindBenchmarks( return true; } -Benchmark* RegisterBenchmarkInternal(std::unique_ptr bench) { - Benchmark* bench_ptr = bench.get(); +benchmark::Benchmark* RegisterBenchmarkInternal( + std::unique_ptr bench) { + benchmark::Benchmark* bench_ptr = bench.get(); BenchmarkFamilies* families = BenchmarkFamilies::GetInstance(); families->AddBenchmark(std::move(bench)); return bench_ptr; @@ -206,13 +208,15 @@ bool FindBenchmarksInternal(const std::string& re, return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err); } +} // end namespace internal + //=============================================================================// // Benchmark //=============================================================================// Benchmark::Benchmark(const std::string& name) : name_(name), - aggregation_report_mode_(ARM_Unspecified), + aggregation_report_mode_(internal::ARM_Unspecified), time_unit_(GetDefaultTimeUnit()), use_default_time_unit_(true), range_multiplier_(kRangeMultiplier), @@ -253,7 +257,7 @@ Benchmark* Benchmark::Unit(TimeUnit unit) { Benchmark* Benchmark::Range(int64_t start, int64_t limit) { BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); std::vector arglist; - AddRange(&arglist, start, limit, range_multiplier_); + internal::AddRange(&arglist, start, limit, range_multiplier_); for (int64_t i : arglist) { args_.push_back({i}); @@ -266,8 +270,8 @@ Benchmark* Benchmark::Ranges( BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast(ranges.size())); std::vector> arglists(ranges.size()); for (std::size_t i = 0; i < ranges.size(); i++) { - AddRange(&arglists[i], ranges[i].first, ranges[i].second, - range_multiplier_); + internal::AddRange(&arglists[i], ranges[i].first, ranges[i].second, + range_multiplier_); } ArgsProduct(arglists); @@ -382,8 +386,8 @@ Benchmark* Benchmark::MinWarmUpTime(double t) { Benchmark* Benchmark::Iterations(IterationCount n) { BM_CHECK(n > 0); - BM_CHECK(IsZero(min_time_)); - BM_CHECK(IsZero(min_warmup_time_)); + BM_CHECK(internal::IsZero(min_time_)); + BM_CHECK(internal::IsZero(min_warmup_time_)); iterations_ = n; return this; } @@ -395,21 +399,23 @@ Benchmark* Benchmark::Repetitions(int n) { } Benchmark* Benchmark::ReportAggregatesOnly(bool value) { - aggregation_report_mode_ = value ? ARM_ReportAggregatesOnly : ARM_Default; + aggregation_report_mode_ = + value ? internal::ARM_ReportAggregatesOnly : internal::ARM_Default; return this; } Benchmark* Benchmark::DisplayAggregatesOnly(bool value) { // If we were called, the report mode is no longer 'unspecified', in any case. + using internal::AggregationReportMode; aggregation_report_mode_ = static_cast( - aggregation_report_mode_ | ARM_Default); + aggregation_report_mode_ | internal::ARM_Default); if (value) { aggregation_report_mode_ = static_cast( - aggregation_report_mode_ | ARM_DisplayReportAggregatesOnly); + aggregation_report_mode_ | internal::ARM_DisplayReportAggregatesOnly); } else { aggregation_report_mode_ = static_cast( - aggregation_report_mode_ & ~ARM_DisplayReportAggregatesOnly); + aggregation_report_mode_ & ~internal::ARM_DisplayReportAggregatesOnly); } return this; @@ -463,7 +469,7 @@ Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) { BM_CHECK_GT(min_threads, 0); BM_CHECK_GE(max_threads, min_threads); - AddRange(&thread_counts_, min_threads, max_threads, 2); + internal::AddRange(&thread_counts_, min_threads, max_threads, 2); return this; } @@ -515,6 +521,8 @@ TimeUnit Benchmark::GetTimeUnit() const { return use_default_time_unit_ ? GetDefaultTimeUnit() : time_unit_; } +namespace internal { + //=============================================================================// // FunctionBenchmark //=============================================================================// diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index d8a2357adc..fb688672a4 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -217,7 +217,8 @@ class ThreadRunnerDefault : public ThreadRunnerBase { }; std::unique_ptr GetThreadRunner( - const threadrunner_factory& userThreadRunnerFactory, int num_threads) { + const benchmark::threadrunner_factory& userThreadRunnerFactory, + int num_threads) { return userThreadRunnerFactory ? userThreadRunnerFactory(num_threads) : std::make_unique(num_threads); diff --git a/test/benchmark_setup_teardown_cb_types_gtest.cc b/test/benchmark_setup_teardown_cb_types_gtest.cc index c5a1a662a2..2ed255dcd3 100644 --- a/test/benchmark_setup_teardown_cb_types_gtest.cc +++ b/test/benchmark_setup_teardown_cb_types_gtest.cc @@ -1,13 +1,13 @@ #include "benchmark/benchmark.h" #include "gtest/gtest.h" +using benchmark::Benchmark; using benchmark::BenchmarkReporter; using benchmark::callback_function; using benchmark::ClearRegisteredBenchmarks; using benchmark::RegisterBenchmark; using benchmark::RunSpecifiedBenchmarks; using benchmark::State; -using benchmark::internal::Benchmark; static int functor_called = 0; struct Functor { diff --git a/test/memory_results_gtest.cc b/test/memory_results_gtest.cc index c40df8f508..70a5a5a985 100644 --- a/test/memory_results_gtest.cc +++ b/test/memory_results_gtest.cc @@ -5,13 +5,13 @@ namespace { +using benchmark::Benchmark; using benchmark::ClearRegisteredBenchmarks; using benchmark::ConsoleReporter; using benchmark::MemoryManager; using benchmark::RegisterBenchmark; using benchmark::RunSpecifiedBenchmarks; using benchmark::State; -using benchmark::internal::Benchmark; constexpr int N_REPETITIONS = 100; constexpr int N_ITERATIONS = 1; diff --git a/test/options_test.cc b/test/options_test.cc index f9dc59b040..70e3e18e2f 100644 --- a/test/options_test.cc +++ b/test/options_test.cc @@ -51,7 +51,7 @@ BENCHMARK(BM_basic)->RangeMultiplier(4)->Range(-8, 8); BENCHMARK(BM_basic)->DenseRange(-2, 2, 1); BENCHMARK(BM_basic)->Ranges({{-64, 1}, {-8, -1}}); -void CustomArgs(benchmark::internal::Benchmark* b) { +void CustomArgs(benchmark::Benchmark* b) { for (int i = 0; i < 10; ++i) { b->Arg(i); } diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index e6f24c2ade..3e39437a27 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -56,7 +56,7 @@ int AddCases(std::initializer_list const& v) { #define ADD_CASES(...) \ const int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__}) -using ReturnVal = benchmark::internal::Benchmark const* const; +using ReturnVal = benchmark::Benchmark const* const; //----------------------------------------------------------------------------// // Test RegisterBenchmark with no additional arguments diff --git a/test/time_unit_gtest.cc b/test/time_unit_gtest.cc index 21fd91b929..0da11092b7 100644 --- a/test/time_unit_gtest.cc +++ b/test/time_unit_gtest.cc @@ -6,7 +6,7 @@ namespace internal { namespace { -class DummyBenchmark : public Benchmark { +class DummyBenchmark : public benchmark::Benchmark { public: DummyBenchmark() : Benchmark("dummy") {} void Run(State& /*state*/) override {} From 494a04fa839b4d9f7ca00868159d2d541f1732a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 01:25:01 +0300 Subject: [PATCH 448/561] Bump actions/cache from 5.0.1 to 5.0.2 (#2104) Bumps [actions/cache](https://github.com/actions/cache) from 5.0.1 to 5.0.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/9255dc7a253b0ccc959486e2bca901246202afeb...8b402f58fbc84540c8b491a91e594a4576fec3d7) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index bf181ba7ef..ab94f16e99 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: mount bazel cache - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 env: cache-name: bazel-cache with: From 5c55f5d4f45a1b09c5d98aa63a671993ebd42c69 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 20 Jan 2026 10:37:18 +0000 Subject: [PATCH 449/561] clang tidy warnings --- include/benchmark/benchmark.h | 1 - src/re.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 3b2015306b..a67a24ef4b 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -171,7 +171,6 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #include #include #include -#include #include #include #include diff --git a/src/re.h b/src/re.h index af4b8bb16e..1486dd8778 100644 --- a/src/re.h +++ b/src/re.h @@ -15,6 +15,8 @@ #ifndef BENCHMARK_RE_H_ #define BENCHMARK_RE_H_ +#include + #include "internal_macros.h" // clang-format off From 31fae1bb246df0d58b53ff8ae15d7d417ce9f315 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 20 Jan 2026 10:51:58 +0000 Subject: [PATCH 450/561] rename to avoid gtest warnings --- test/{overload_gtest.cc => overload_test.cc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{overload_gtest.cc => overload_test.cc} (100%) diff --git a/test/overload_gtest.cc b/test/overload_test.cc similarity index 100% rename from test/overload_gtest.cc rename to test/overload_test.cc From aa3ed62f601993f8b662f639b1bf9033bfb21067 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 21 Jan 2026 12:42:30 +0000 Subject: [PATCH 451/561] pin bazelversion to pre-9 --- .bazelversion | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bazelversion diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000000..2b0aa21219 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +8.2.1 From d8db2f90b643eb28a12976beb4d57bcfb639911d Mon Sep 17 00:00:00 2001 From: Kostiantyn Lazukin Date: Wed, 21 Jan 2026 13:15:42 +0000 Subject: [PATCH 452/561] Silence -Wc2y-extensions warning around __COUNTER__ (#2108) clang-23 in pedantic mode now warns that __COUNTER__ macro is c2y extension. This patch silences this warning around uses of this macro. Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- AUTHORS | 1 + CONTRIBUTORS | 1 + include/benchmark/benchmark.h | 22 ++++++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index ef905531df..11d28f7229 100644 --- a/AUTHORS +++ b/AUTHORS @@ -44,6 +44,7 @@ Jordan Williams Jussi Knuuttila Kaito Udagawa Kishan Kumar +Kostiantyn Lazukin Lei Xu Marcel Jacobse Matt Clarkson diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4b015925aa..52e49cce46 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -67,6 +67,7 @@ Jussi Knuuttila Kaito Udagawa Kai Wolf Kishan Kumar +Kostiantyn Lazukin Lei Xu Marcel Jacobse Matt Clarkson diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index a67a24ef4b..f7d1341c8f 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1484,14 +1484,29 @@ class Fixture : public Benchmark { // ------------------------------------------------------ // Macro to register benchmarks +// clang-format off +#if defined(__clang__) +#define BENCHMARK_DISABLE_COUNTER_WARNING \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunknown-warning-option\"") \ + _Pragma("GCC diagnostic ignored \"-Wc2y-extensions\"") +#define BENCHMARK_RESTORE_COUNTER_WARNING _Pragma("GCC diagnostic pop") +#else +#define BENCHMARK_DISABLE_COUNTER_WARNING +#define BENCHMARK_RESTORE_COUNTER_WARNING +#endif +// clang-format on + // Check that __COUNTER__ is defined and that __COUNTER__ increases by 1 // every time it is expanded. X + 1 == X + 0 is used in case X is defined to be // empty. If X is empty the expression becomes (+1 == +0). +BENCHMARK_DISABLE_COUNTER_WARNING #if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) #define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__ #else #define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__ #endif +BENCHMARK_RESTORE_COUNTER_WARNING // Helpers for generating unique variable names #define BENCHMARK_PRIVATE_NAME(...) \ @@ -1505,9 +1520,10 @@ class Fixture : public Benchmark { BaseClass##_##Method##_Benchmark #define BENCHMARK_PRIVATE_DECLARE(n) \ + BENCHMARK_DISABLE_COUNTER_WARNING \ /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ static ::benchmark::Benchmark const* const BENCHMARK_PRIVATE_NAME(n) \ - BENCHMARK_UNUSED + BENCHMARK_RESTORE_COUNTER_WARNING BENCHMARK_UNUSED #define BENCHMARK(...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ @@ -1695,9 +1711,11 @@ class Fixture : public Benchmark { ::benchmark::internal::make_unique())) #define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \ + BENCHMARK_DISABLE_COUNTER_WARNING \ BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \ BaseClass, Method, BENCHMARK_PRIVATE_NAME(BaseClass##Method), \ - __VA_ARGS__) + __VA_ARGS__) \ + BENCHMARK_RESTORE_COUNTER_WARNING // This macro will define and register a benchmark within a fixture class. #define BENCHMARK_F(BaseClass, Method) \ From 192ef10025eb2c4cdd392bc502f0c852196baa48 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Wed, 21 Jan 2026 13:16:48 +0000 Subject: [PATCH 453/561] version bump to 1.9.5 --- CMakeLists.txt | 2 +- MODULE.bazel | 2 +- bindings/python/google_benchmark/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e50eec91e..ada04a61c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Require CMake 3.10. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.13...3.22) -project (benchmark VERSION 1.9.4 LANGUAGES CXX) +project (benchmark VERSION 1.9.5 LANGUAGES CXX) option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON) option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) diff --git a/MODULE.bazel b/MODULE.bazel index 620e3d030f..c162d05313 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "google_benchmark", - version = "1.9.4", + version = "1.9.5", ) bazel_dep(name = "bazel_skylib", version = "1.7.1") diff --git a/bindings/python/google_benchmark/__init__.py b/bindings/python/google_benchmark/__init__.py index 040bdff0c7..331a88e9b5 100644 --- a/bindings/python/google_benchmark/__init__.py +++ b/bindings/python/google_benchmark/__init__.py @@ -48,7 +48,7 @@ def my_benchmark(state): oNSquared as oNSquared, ) -__version__ = "1.9.4" +__version__ = "1.9.5" class __OptionMaker: From 97ad7f116d15d0408980d068067e2ae37ea5f2dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:06:48 +0000 Subject: [PATCH 454/561] Bump actions/checkout from 6.0.1 to 6.0.2 (#2111) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8e8c483db84b4bee98b60c0593521ed34d9990e8...de0fac2e4500dabe0009e67214ff5f5447ce83dd) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index ab94f16e99..5f2c990952 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: mount bazel cache uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index c9d6e049ab..4ccfbd5ddc 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,7 +19,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index df2ff34643..81b4170fee 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 90215c5abf..2599890f7a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,7 +30,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -77,7 +77,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index c9f0315f60..6f29b973a6 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index 1c92cfc1f6..20a077f096 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 075a385d32..4cfd99c9f1 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index db742fb0f7..8c3db2e133 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Run analysis uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index f6300601d6..26e18b2258 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 6e9404f090..8024752989 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: configure msan env if: matrix.sanitizer == 'msan' diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 191239c6a7..b79f5863d2 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c0c8eab565..92f2f17fe8 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Install Python 3.12 @@ -38,7 +38,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 From a86573f4ea8375c930ee285b63315c2e611a1d95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:19:49 +0000 Subject: [PATCH 455/561] Bump lukka/get-cmake from 4.2.1 to 4.2.2 (#2110) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/9e07ecdcee1b12e5037e42f410b67f03e2f626e1...dc05ee1ee5ba69770230c73a6a4e947595745cab) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.2.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 4ccfbd5ddc..d1014ee88e 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest + - uses: lukka/get-cmake@dc05ee1ee5ba69770230c73a6a4e947595745cab # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2599890f7a..106b99b887 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # latest + - uses: lukka/get-cmake@dc05ee1ee5ba69770230c73a6a4e947595745cab # latest - name: configure cmake run: > From 03325caf07994bccef7497666dae4670ec0f89cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:32:30 +0000 Subject: [PATCH 456/561] Bump actions/setup-python from 6.1.0 to 6.2.0 (#2112) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.1.0 to 6.2.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/83679a892e2d95755f2dac6acb0bfd1e9ac5d548...a309ff8b426b58ec0e2a45f0f869d46889d02405) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 6.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index b79f5863d2..016a6b2d9e 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -27,7 +27,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Install GBM Python bindings on ${{ matrix.os }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 92f2f17fe8..26312c9373 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -19,7 +19,7 @@ jobs: with: fetch-depth: 0 - name: Install Python 3.12 - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" - run: python -m pip install build @@ -42,7 +42,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 name: Install Python 3.12 with: python-version: "3.12" From ed7081dd9d7c2aad4c3757485855f26813be6be2 Mon Sep 17 00:00:00 2001 From: Osama131 <33330181+Osama131@users.noreply.github.com> Date: Wed, 28 Jan 2026 17:19:48 +0100 Subject: [PATCH 457/561] exclude linking to lib rt for QNX to avoid linking error (#2114) --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ada04a61c4..a450a349e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,12 @@ include(CheckCXXCompilerFlag) include(CheckLibraryExists) include(CXXFeatureCheck) -check_library_exists(rt shm_open "" HAVE_LIB_RT) +# Check for rt library, but explicitly disable for QNX +if(QNXNTO) + set(HAVE_LIB_RT FALSE) +else() + check_library_exists(rt shm_open "" HAVE_LIB_RT) +endif() if (BENCHMARK_BUILD_32_BITS) add_required_cxx_compiler_flag(-m32) From 4dbe0f4046e4351aeced195712067f4a6e13a16f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 10:04:39 +0000 Subject: [PATCH 458/561] Bump lukka/get-cmake from 4.2.2 to 4.2.3 (#2115) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.2.2 to 4.2.3. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/dc05ee1ee5ba69770230c73a6a4e947595745cab...f176ccd3f28bda569c43aae4894f06b2435a3375) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.2.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index d1014ee88e..72d9e7d3a1 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@dc05ee1ee5ba69770230c73a6a4e947595745cab # latest + - uses: lukka/get-cmake@f176ccd3f28bda569c43aae4894f06b2435a3375 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 106b99b887..e3ea001390 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@dc05ee1ee5ba69770230c73a6a4e947595745cab # latest + - uses: lukka/get-cmake@f176ccd3f28bda569c43aae4894f06b2435a3375 # latest - name: configure cmake run: > From 4ed29ae27492e63acd2500a3b7b76bcfefc44f10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 12:12:14 +0000 Subject: [PATCH 459/561] Bump actions/cache from 5.0.2 to 5.0.3 (#2116) Bumps [actions/cache](https://github.com/actions/cache) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/8b402f58fbc84540c8b491a91e594a4576fec3d7...cdf6c1fa76f9f475f3d7449005a359c84ca0f306) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 5f2c990952..aab9aebd2f 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: mount bazel cache - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 env: cache-name: bazel-cache with: From 471fb2ccf8d25b1f1278aaa9d3bc599ad8da5e47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Feb 2026 11:31:44 +0000 Subject: [PATCH 460/561] Bump astral-sh/setup-uv from 7.2.0 to 7.2.1 (#2119) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.2.0 to 7.2.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/61cb8a9741eeb8a550a1b8544337180c0fc8476b...803947b9bd8e9f986429fa0c5a41c367cd732b41) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 26e18b2258..8f6ef36d2c 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0 + uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 26312c9373..4ba2bdd7fd 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0 + uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e # v3.3.1 From 016bef300d6159be3915629b9a74ddca45c127fc Mon Sep 17 00:00:00 2001 From: Nicholas Junge Date: Mon, 2 Feb 2026 13:07:13 +0100 Subject: [PATCH 461/561] fix(pyproject): Update license to SPDX identifier (#2120) Silences a warning in newer setuptools. The changes are as per the recommendation in Python's packaging guide, see https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license-and-license-files. --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f55daf2606..24b4f7407b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "google_benchmark" description = "A library to benchmark code snippets." requires-python = ">=3.10" -license = { file = "LICENSE" } +license = "Apache-2.0" keywords = ["benchmark"] authors = [{ name = "Google", email = "benchmark-discuss@googlegroups.com" }] @@ -15,7 +15,6 @@ classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Science/Research", - "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", From eed8f5c682ed70d596b2b07c68b1588ecab3b24a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:11:42 +0000 Subject: [PATCH 462/561] Bump numpy from 2.4.1 to 2.4.2 in /tools (#2121) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.1 to 2.4.2. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.1...v2.4.2) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 12d5d9ce99..33648c0571 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.4.1 +numpy == 2.4.2 scipy == 1.17.0 From 78a9d85dfa12ca6ce5c05613e622321c626f49ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:56:10 +0000 Subject: [PATCH 463/561] Bump astral-sh/setup-uv from 7.2.1 to 7.3.0 (#2122) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.2.1 to 7.3.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/803947b9bd8e9f986429fa0c5a41c367cd732b41...eac588ad8def6316056a12d4907a9d4d84ff7a3b) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 8f6ef36d2c..facd162d4e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 + uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4ba2bdd7fd..359a7380aa 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 + uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e # v3.3.1 From 84732c8bb2efe96bc87766737d29456a01b1d7e2 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 11 Feb 2026 02:07:17 -0800 Subject: [PATCH 464/561] Replicate generic hardware events on all CPU PMUs (#2123) On systems with more than one PMU for the CPUs (e.g. Apple M series SOCs), generic hardware events are only created for an arbitrary PMU. Usually this is the big cluster's PMU, which can cause inaccuracies when the process is scheduled onto a little core. To fix this, teach PerfCounters to register generic hardware events on all CPU PMUs. CPU PMUs are identified using the same method as perf. --- src/perf_counters.cc | 137 ++++++++++++++++++++++---------- src/perf_counters.h | 2 +- test/perf_counters_gtest.cc | 151 ++++++++++++++++++++++++++---------- 3 files changed, 209 insertions(+), 81 deletions(-) diff --git a/src/perf_counters.cc b/src/perf_counters.cc index f47aa7b42d..e6f220921c 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -16,9 +16,15 @@ #include #include +#include #include #if defined HAVE_LIBPFM +#include +#include +#include +#include + #include "perfmon/pfmlib.h" #include "perfmon/pfmlib_perf_event.h" #endif @@ -68,7 +74,7 @@ bool PerfCounters::Initialize() { bool PerfCounters::IsCounterSupported(const std::string& name) { Initialize(); - perf_event_attr_t attr; + perf_event_attr attr; std::memset(&attr, 0, sizeof(attr)); pfm_perf_encode_arg_t arg; std::memset(&arg, 0, sizeof(arg)); @@ -79,6 +85,55 @@ bool PerfCounters::IsCounterSupported(const std::string& name) { return (ret == PFM_SUCCESS); } +static std::optional> QueryCPUPMUTypes() { + std::vector types; + DIR* dir = opendir("/sys/bus/event_source/devices"); + if (!dir) { + return std::nullopt; + } + while (dirent* ent = readdir(dir)) { + std::string_view name_str = ent->d_name; + auto node_path = [&](const char* node) { + return std::string("/sys/bus/event_source/devices/") + ent->d_name + "/" + + node; + }; + struct stat st; + if (name_str == "cpu" || name_str == "cpum_cf" || + stat(node_path("cpus").c_str(), &st) == 0 || errno != ENOENT) { + int type_fd = open(node_path("type").c_str(), O_RDONLY); + if (type_fd < 0) { + closedir(dir); + return std::nullopt; + } + char type_str[32] = {}; + ssize_t res = read(type_fd, type_str, sizeof(type_str) - 1); + close(type_fd); + if (res < 0) { + closedir(dir); + return std::nullopt; + } + uint64_t type; + if (sscanf(type_str, "%" PRIu64, &type) != 1) { + closedir(dir); + return std::nullopt; + } + types.push_back(type); + } + } + closedir(dir); + return types; +} + +static std::vector GetPMUTypesForEvent(const perf_event_attr& attr) { + // Replicate generic hardware events on all CPU PMUs. + if (attr.type == PERF_TYPE_HARDWARE && attr.config < PERF_COUNT_HW_MAX) { + if (auto types = QueryCPUPMUTypes()) { + return *types; + } + } + return {0}; +} + PerfCounters PerfCounters::Create( const std::vector& counter_names) { if (!counter_names.empty()) { @@ -158,50 +213,54 @@ PerfCounters PerfCounters::Create( attr.read_format = PERF_FORMAT_GROUP; //| PERF_FORMAT_TOTAL_TIME_ENABLED | // PERF_FORMAT_TOTAL_TIME_RUNNING; - int id = -1; - while (id < 0) { - static constexpr size_t kNrOfSyscallRetries = 5; - // Retry syscall as it was interrupted often (b/64774091). - for (size_t num_retries = 0; num_retries < kNrOfSyscallRetries; - ++num_retries) { - id = perf_event_open(&attr, 0, -1, group_id, 0); - if (id >= 0 || errno != EINTR) { - break; + uint64_t base_config = attr.config; + for (uint64_t pmu : GetPMUTypesForEvent(attr)) { + attr.config = (pmu << PERF_PMU_TYPE_SHIFT) | base_config; + int id = -1; + while (id < 0) { + static constexpr size_t kNrOfSyscallRetries = 5; + // Retry syscall as it was interrupted often (b/64774091). + for (size_t num_retries = 0; num_retries < kNrOfSyscallRetries; + ++num_retries) { + id = perf_event_open(&attr, 0, -1, group_id, 0); + if (id >= 0 || errno != EINTR) { + break; + } } - } - if (id < 0) { - // If the file descriptor is negative we might have reached a limit - // in the current group. Set the group_id to -1 and retry - if (group_id >= 0) { - // Create a new group - group_id = -1; - } else { - // At this point we have already retried to set a new group id and - // failed. We then give up. - break; + if (id < 0) { + // If the file descriptor is negative we might have reached a limit + // in the current group. Set the group_id to -1 and retry + if (group_id >= 0) { + // Create a new group + group_id = -1; + } else { + // At this point we have already retried to set a new group id and + // failed. We then give up. + break; + } } } - } - // We failed to get a new file descriptor. We might have reached a hard - // hardware limit that cannot be resolved even with group multiplexing - if (id < 0) { - GetErrorLogInstance() << "***WARNING** Failed to get a file descriptor " - "for performance counter " - << name << ". Ignoring\n"; + // We failed to get a new file descriptor. We might have reached a hard + // hardware limit that cannot be resolved even with group multiplexing + if (id < 0) { + GetErrorLogInstance() << "***WARNING** Failed to get a file descriptor " + "for performance counter " + << name << ". Ignoring\n"; - // We give up on this counter but try to keep going - // as the others would be fine - continue; - } - if (group_id < 0) { - // This is a leader, store and assign it to the current file descriptor - leader_ids.push_back(id); - group_id = id; + // We give up on this counter but try to keep going + // as the others would be fine + continue; + } + if (group_id < 0) { + // This is a leader, store and assign it to the current file descriptor + leader_ids.push_back(id); + group_id = id; + } + // This is a valid counter, add it to our descriptor's list + counter_ids.push_back(id); + valid_names.push_back(name); } - // This is a valid counter, add it to our descriptor's list - counter_ids.push_back(id); - valid_names.push_back(name); } // Loop through all group leaders activating them diff --git a/src/perf_counters.h b/src/perf_counters.h index bf5eb6bc3a..4e45344318 100644 --- a/src/perf_counters.h +++ b/src/perf_counters.h @@ -152,7 +152,7 @@ class BENCHMARK_EXPORT PerfCountersMeasurement final { size_t num_counters() const { return counters_.num_counters(); } - std::vector names() const { return counters_.names(); } + const std::vector& names() const { return counters_.names(); } BENCHMARK_ALWAYS_INLINE bool Start() { if (num_counters() == 0) return true; diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index 5de262fa2b..6c923be897 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -27,12 +27,22 @@ TEST(PerfCountersTest, Init) { EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported); } +// Generic events will have as many counters as there are CPU PMUs, and each +// will have the same name. In order to make these tests independent of the +// number of CPU PMUs in the system, we uniquify the counter names before +// testing them. +static std::set UniqueCounterNames(const PerfCounters& pc) { + std::set names{pc.names().begin(), pc.names().end()}; + return names; +} + TEST(PerfCountersTest, OneCounter) { if (!PerfCounters::kSupported) { GTEST_SKIP() << "Performance counters not supported.\n"; } EXPECT_TRUE(PerfCounters::Initialize()); - EXPECT_EQ(PerfCounters::Create({kGenericPerfEvent1}).num_counters(), 1); + EXPECT_EQ( + UniqueCounterNames(PerfCounters::Create({kGenericPerfEvent1})).size(), 1); } TEST(PerfCountersTest, NegativeTest) { @@ -53,32 +63,49 @@ TEST(PerfCountersTest, NegativeTest) { // number of counters has to be two, not zero auto counter = PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1}); - EXPECT_EQ(counter.num_counters(), 2); - EXPECT_EQ(counter.names(), std::vector( - {kGenericPerfEvent2, kGenericPerfEvent1})); + auto names = UniqueCounterNames(counter); + EXPECT_EQ(names.size(), 2); + EXPECT_EQ(names, + std::set({kGenericPerfEvent2, kGenericPerfEvent1})); } { // Try sneaking in an outrageous counter, like a fat finger mistake auto counter = PerfCounters::Create( {kGenericPerfEvent2, "not a counter name", kGenericPerfEvent1}); - EXPECT_EQ(counter.num_counters(), 2); - EXPECT_EQ(counter.names(), std::vector( - {kGenericPerfEvent2, kGenericPerfEvent1})); + auto names = UniqueCounterNames(counter); + EXPECT_EQ(names.size(), 2); + EXPECT_EQ(names, + std::set({kGenericPerfEvent2, kGenericPerfEvent1})); } { // Finally try a golden input - it should like both of them - EXPECT_EQ(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}) - .num_counters(), + EXPECT_EQ(UniqueCounterNames(PerfCounters::Create( + {kGenericPerfEvent1, kGenericPerfEvent2})) + .size(), 2); } { // Add a bad apple in the end of the chain to check the edges auto counter = PerfCounters::Create( {kGenericPerfEvent1, kGenericPerfEvent2, "bad event name"}); - EXPECT_EQ(counter.num_counters(), 2); - EXPECT_EQ(counter.names(), std::vector( - {kGenericPerfEvent1, kGenericPerfEvent2})); + auto names = UniqueCounterNames(counter); + EXPECT_EQ(names.size(), 2); + EXPECT_EQ(names, + std::set({kGenericPerfEvent1, kGenericPerfEvent2})); + } +} + +static std::map SnapshotAndCombine( + PerfCounters& counters) { + PerfCounterValues values(counters.num_counters()); + std::map value_map; + + if (counters.Snapshot(&values)) { + for (size_t i = 0; i != counters.num_counters(); ++i) { + value_map[counters.names()[i]] += values[i]; + } } + return value_map; } TEST(PerfCountersTest, Read1Counter) { @@ -87,14 +114,50 @@ TEST(PerfCountersTest, Read1Counter) { } EXPECT_TRUE(PerfCounters::Initialize()); auto counters = PerfCounters::Create({kGenericPerfEvent1}); - EXPECT_EQ(counters.num_counters(), 1); - PerfCounterValues values1(1); - EXPECT_TRUE(counters.Snapshot(&values1)); - EXPECT_GT(values1[0], 0); - PerfCounterValues values2(1); - EXPECT_TRUE(counters.Snapshot(&values2)); - EXPECT_GT(values2[0], 0); - EXPECT_GT(values2[0], values1[0]); + auto values1 = SnapshotAndCombine(counters); + EXPECT_EQ(values1.size(), 1); + EXPECT_GT(values1.begin()->second, 0); + auto values2 = SnapshotAndCombine(counters); + EXPECT_EQ(values2.size(), 1); + EXPECT_GT(values2.begin()->second, 0); + EXPECT_GT(values2.begin()->second, values1.begin()->second); +} + +TEST(PerfCountersTest, Read1CounterEachCPU) { + if (!PerfCounters::kSupported) { + GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + } +#ifdef __linux__ + EXPECT_TRUE(PerfCounters::Initialize()); + + cpu_set_t saved_set; + if (sched_getaffinity(0, sizeof(saved_set), &saved_set) != 0) { + // This can happen e.g. if there are more than CPU_SETSIZE CPUs. + GTEST_SKIP() << "Could not save CPU affinity mask.\n"; + } + + for (size_t cpu = 0; cpu != CPU_SETSIZE; ++cpu) { + cpu_set_t set; + CPU_ZERO(&set); + CPU_SET(cpu, &set); + if (sched_setaffinity(0, sizeof(set), &set) != 0) { + break; + } + + auto counters = PerfCounters::Create({kGenericPerfEvent1}); + auto values1 = SnapshotAndCombine(counters); + EXPECT_EQ(values1.size(), 1); + EXPECT_GT(values1.begin()->second, 0); + auto values2 = SnapshotAndCombine(counters); + EXPECT_EQ(values2.size(), 1); + EXPECT_GT(values2.begin()->second, 0); + EXPECT_GT(values2.begin()->second, values1.begin()->second); + } + + EXPECT_EQ(sched_setaffinity(0, sizeof(saved_set), &saved_set), 0); +#else + GTEST_SKIP() << "Test skipped on non-Linux.\n"; +#endif } TEST(PerfCountersTest, Read2Counters) { @@ -104,15 +167,17 @@ TEST(PerfCountersTest, Read2Counters) { EXPECT_TRUE(PerfCounters::Initialize()); auto counters = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}); - EXPECT_EQ(counters.num_counters(), 2); - PerfCounterValues values1(2); - EXPECT_TRUE(counters.Snapshot(&values1)); - EXPECT_GT(values1[0], 0); - EXPECT_GT(values1[1], 0); - PerfCounterValues values2(2); - EXPECT_TRUE(counters.Snapshot(&values2)); - EXPECT_GT(values2[0], 0); - EXPECT_GT(values2[1], 0); + auto values1 = SnapshotAndCombine(counters); + EXPECT_EQ(values1.size(), 2); + for (auto& kv : values1) { + EXPECT_GT(kv.second, 0); + } + auto values2 = SnapshotAndCombine(counters); + EXPECT_EQ(values1.size(), 2); + for (auto& kv : values2) { + EXPECT_GT(kv.second, 0); + EXPECT_GT(kv.second, values1[kv.first]); + } } TEST(PerfCountersTest, ReopenExistingCounters) { @@ -127,7 +192,7 @@ TEST(PerfCountersTest, ReopenExistingCounters) { for (auto& counter : counters) { counter = PerfCounters::Create(kMetrics); } - PerfCounterValues values(1); + PerfCounterValues values(counters[0].num_counters()); EXPECT_TRUE(counters[0].Snapshot(&values)); EXPECT_TRUE(counters[1].Snapshot(&values)); } @@ -171,7 +236,8 @@ TEST(PerfCountersTest, CreateExistingMeasurements) { size_t max_counters = kMaxCounters; for (size_t i = 0; i < kMaxCounters; ++i) { auto& counter(*perf_counter_measurements[i]); - EXPECT_EQ(counter.num_counters(), 1); + std::set names{counter.names().begin(), counter.names().end()}; + EXPECT_EQ(names.size(), 1); if (!counter.Start()) { max_counters = i; break; @@ -212,8 +278,8 @@ BENCHMARK_DONT_OPTIMIZE size_t do_work() { return sum; } -void measure(size_t threadcount, PerfCounterValues* before, - PerfCounterValues* after) { +void measure(size_t threadcount, std::map* before, + std::map* after) { BM_CHECK_NE(before, nullptr); BM_CHECK_NE(after, nullptr); std::vector threads(threadcount); @@ -229,11 +295,11 @@ void measure(size_t threadcount, PerfCounterValues* before, for (auto& t : threads) { t = std::thread(work); } - counters.Snapshot(before); + *before = SnapshotAndCombine(counters); for (auto& t : threads) { t.join(); } - counters.Snapshot(after); + *after = SnapshotAndCombine(counters); } TEST(PerfCountersTest, MultiThreaded) { @@ -241,8 +307,7 @@ TEST(PerfCountersTest, MultiThreaded) { GTEST_SKIP() << "Test skipped because libpfm is not supported."; } EXPECT_TRUE(PerfCounters::Initialize()); - PerfCounterValues before(2); - PerfCounterValues after(2); + std::map before, after; // Notice that this test will work even if we taskset it to a single CPU // In this case the threads will run sequentially @@ -250,15 +315,19 @@ TEST(PerfCountersTest, MultiThreaded) { // instructions measure(2, &before, &after); std::vector Elapsed2Threads{ - static_cast(after[0] - before[0]), - static_cast(after[1] - before[1])}; + static_cast(after[kGenericPerfEvent1] - + before[kGenericPerfEvent1]), + static_cast(after[kGenericPerfEvent2] - + before[kGenericPerfEvent2])}; // Start four threads and measure the number of combined cycles and // instructions measure(4, &before, &after); std::vector Elapsed4Threads{ - static_cast(after[0] - before[0]), - static_cast(after[1] - before[1])}; + static_cast(after[kGenericPerfEvent1] - + before[kGenericPerfEvent1]), + static_cast(after[kGenericPerfEvent2] - + before[kGenericPerfEvent2])}; // The following expectations fail (at least on a beefy workstation with lots // of cpus) - it seems that in some circumstances the runtime of 4 threads From 559b7cc1aec1950a9e3f4e879b08cf0b00f796f0 Mon Sep 17 00:00:00 2001 From: Sergey Date: Fri, 13 Feb 2026 06:32:08 -0700 Subject: [PATCH 465/561] Fix error: format string is not a string literal (#2126) (#2126) For some reasons, `std::string StrFormat(const char* format, ...)` was declared with castom format attributes in conditions. The project wide macro `PRINTF_FORMAT_STRING_FUNC` must be used. --- src/string_util.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/string_util.h b/src/string_util.h index f1e50be4f4..7a2ce0ba79 100644 --- a/src/string_util.h +++ b/src/string_util.h @@ -16,13 +16,7 @@ BENCHMARK_EXPORT std::string HumanReadableNumber(double n, Counter::OneK one_k); BENCHMARK_EXPORT -#if defined(__MINGW32__) -__attribute__((format(__MINGW_PRINTF_FORMAT, 1, 2))) -#elif defined(__GNUC__) -__attribute__((format(printf, 1, 2))) -#endif -std::string -StrFormat(const char* format, ...); +std::string StrFormat(const char* format, ...) PRINTF_FORMAT_STRING_FUNC(1, 2); inline std::ostream& StrCatImp(std::ostream& out) BENCHMARK_NOEXCEPT { return out; From 7da00e8f6763d6e8c284d172c9cfcc5ae0ce9b7a Mon Sep 17 00:00:00 2001 From: Dillon Date: Mon, 16 Feb 2026 20:00:21 -0800 Subject: [PATCH 466/561] Revert "Remove redundant feature checks on re-run of CMake config step (#2084)" (#2127) This reverts commit 6a8dee95ae1151142fe4be94482cdfd11b7111bd. --- CMakeLists.txt | 13 +--- cmake/CXXFeatureCheck.cmake | 114 +++++++++++++++--------------------- 2 files changed, 51 insertions(+), 76 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a450a349e7..11d24961c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,17 +315,10 @@ if (BENCHMARK_USE_LIBCXX) endif(BENCHMARK_USE_LIBCXX) # C++ feature checks -# Determine the correct regular expression engine to use. First compatible engine found is used. +# Determine the correct regular expression engine to use cxx_feature_check(STD_REGEX) - -if(NOT HAVE_STD_REGEX) - cxx_feature_check(GNU_POSIX_REGEX) -endif() - -if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX) - cxx_feature_check(POSIX_REGEX) -endif() - +cxx_feature_check(GNU_POSIX_REGEX) +cxx_feature_check(POSIX_REGEX) if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX) message(FATAL_ERROR "Failed to determine the source files for the regular expression backend") endif() diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index a163a6e094..ee5b7591e2 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -10,35 +10,22 @@ # # include(CXXFeatureCheck) # cxx_feature_check(STD_REGEX) -# Requires CMake 3.13+ +# Requires CMake 2.8.12+ if(__cxx_feature_check) return() endif() set(__cxx_feature_check INCLUDED) -option(CXXFEATURECHECK_DEBUG OFF "Enable debug messages for CXX feature checks") +option(CXXFEATURECHECK_DEBUG OFF) -function(cxx_feature_check_print log) - if(CXXFEATURECHECK_DEBUG) - message(STATUS "${log}") - endif() -endfunction() - -function(cxx_feature_check FEATURE) - string(TOLOWER ${FEATURE} FILE) - string(TOUPPER HAVE_${FEATURE} VAR) - - # Check if the variable is already defined to a true or false for a quick return. - # This allows users to predefine the variable to skip the check. - # Or, if the variable is already defined by a previous check, we skip the costly check. - if (DEFINED ${VAR}) - if (${VAR}) - cxx_feature_check_print("Feature ${FEATURE} already enabled.") - add_compile_definitions(${VAR}) - else() - cxx_feature_check_print("Feature ${FEATURE} already disabled.") - endif() +function(cxx_feature_check FILE) + string(TOLOWER ${FILE} FILE) + string(TOUPPER ${FILE} VAR) + string(TOUPPER "HAVE_${VAR}" FEATURE) + if (DEFINED HAVE_${VAR}) + set(HAVE_${VAR} 1 PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) return() endif() @@ -48,53 +35,48 @@ function(cxx_feature_check FEATURE) list(APPEND FEATURE_CHECK_CMAKE_FLAGS ${ARGV1}) endif() - if(CMAKE_CROSSCOMPILING) - cxx_feature_check_print("Cross-compiling to test ${FEATURE}") - try_compile( - COMPILE_STATUS - ${CMAKE_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON - CMAKE_FLAGS "${FEATURE_CHECK_CMAKE_FLAGS}" - LINK_LIBRARIES "${BENCHMARK_CXX_LIBRARIES}" - OUTPUT_VARIABLE COMPILE_OUTPUT_VAR - ) - if(COMPILE_STATUS) - set(RUN_STATUS 0) - message(WARNING - "If you see build failures due to cross compilation, try setting ${VAR} to 0") + if (NOT DEFINED COMPILE_${FEATURE}) + if(CMAKE_CROSSCOMPILING) + message(STATUS "Cross-compiling to test ${FEATURE}") + try_compile(COMPILE_${FEATURE} + ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} + LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} + OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) + if(COMPILE_${FEATURE}) + message(WARNING + "If you see build failures due to cross compilation, try setting HAVE_${VAR} to 0") + set(RUN_${FEATURE} 0 CACHE INTERNAL "") + else() + set(RUN_${FEATURE} 1 CACHE INTERNAL "") + endif() + else() + message(STATUS "Compiling and running to test ${FEATURE}") + try_run(RUN_${FEATURE} COMPILE_${FEATURE} + ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CMAKE_FLAGS ${FEATURE_CHECK_CMAKE_FLAGS} + LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES} + COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR) endif() - else() - cxx_feature_check_print("Compiling and running to test ${FEATURE}") - try_run( - RUN_STATUS - COMPILE_STATUS - ${CMAKE_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON - CMAKE_FLAGS "${FEATURE_CHECK_CMAKE_FLAGS}" - LINK_LIBRARIES "${BENCHMARK_CXX_LIBRARIES}" - COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT - RUN_OUTPUT_VARIABLE RUN_OUTPUT - ) endif() - if(COMPILE_STATUS AND RUN_STATUS EQUAL 0) - message(STATUS "Performing Test ${FEATURE} -- success") - set(${VAR} TRUE CACHE BOOL "" FORCE) - add_compile_definitions(${VAR}) - return() - endif() - - set(${VAR} FALSE CACHE BOOL "" FORCE) - message(STATUS "Performing Test ${FEATURE} -- failed") - - if(NOT COMPILE_STATUS) - cxx_feature_check_print("Compile Output: ${COMPILE_OUTPUT}") + if(COMPILE_${FEATURE}) + if(DEFINED RUN_${FEATURE} AND RUN_${FEATURE} EQUAL 0) + message(STATUS "Performing Test ${FEATURE} -- success") + set(HAVE_${VAR} 1 PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) + else() + message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run") + endif() else() - cxx_feature_check_print("Run Output: ${RUN_OUTPUT}") + if(CXXFEATURECHECK_DEBUG) + message(STATUS "Performing Test ${FEATURE} -- failed to compile: ${COMPILE_OUTPUT_VAR}") + else() + message(STATUS "Performing Test ${FEATURE} -- failed to compile") + endif() endif() - endfunction() From 6ebb28710424e07e6f35308f2a3997e34bedd6b8 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Sat, 21 Feb 2026 11:12:45 +0000 Subject: [PATCH 467/561] Bump the version of python used for pip. (#2130) The default python is already 3.12 (widely available) and we should use the same default for the pip calls too. It's tricky to get older python versions sometimes so this should simplify things. --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index c162d05313..ad3df4a4f5 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -31,7 +31,7 @@ python.toolchain(python_version = "3.13") pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) pip.parse( hub_name = "tools_pip_deps", - python_version = "3.9", + python_version = "3.12", requirements_lock = "//tools:requirements.txt", ) use_repo(pip, "tools_pip_deps") From 8b14531fc59934c703c3ab3576f29b178f494fb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:59:40 +0000 Subject: [PATCH 468/561] Bump scipy from 1.17.0 to 1.17.1 in /tools (#2132) Bumps [scipy](https://github.com/scipy/scipy) from 1.17.0 to 1.17.1. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.17.0...v1.17.1) --- updated-dependencies: - dependency-name: scipy dependency-version: 1.17.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 33648c0571..b2ef85c1b3 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ numpy == 2.4.2 -scipy == 1.17.0 +scipy == 1.17.1 From a2e384c8a82991f47f8dc9057baa5a0919c73658 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 03:38:49 +0300 Subject: [PATCH 469/561] Bump actions/upload-artifact from 6.0.0 to 7.0.0 (#2133) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/b7c566a772e6b6bfb58ed0dc250532a479d7789f...bbbca2ddaa5d8feaa63e36b76fdaad77386f024f) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 359a7380aa..e9172b47e0 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -25,7 +25,7 @@ jobs: - run: python -m pip install build - name: Build sdist run: python -m build --sdist - - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: dist-sdist path: dist/*.tar.gz @@ -64,7 +64,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-15-intel' && 10.14 || 11.0 }} - name: Upload Google Benchmark ${{ matrix.os }} wheels - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: dist-${{ matrix.os }} path: wheelhouse/*.whl From 5b9fd109b1e9e1a180fde5025477de6870bb48cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 03:46:09 +0300 Subject: [PATCH 470/561] Bump actions/download-artifact from 7.0.0 to 8.0.0 (#2134) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7.0.0 to 8.0.0. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/37930b1c2abaa49bbe596cd826c3c89aef350131...70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 8.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e9172b47e0..6f5593cfc6 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -76,7 +76,7 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: path: dist pattern: dist-* From fbb750d797066fb760c01b63b08162bc54a6f5b7 Mon Sep 17 00:00:00 2001 From: Ben King <126735454+5kng@users.noreply.github.com> Date: Fri, 27 Feb 2026 23:01:58 +1100 Subject: [PATCH 471/561] Add BENCHMARK_NAMED macro for named benchmarks without lambda (#2135) * Add BENCHMARK_NAMED macro for named benchmarks without lambda Closes #2128. BENCHMARK_CAPTURE creates a lambda even when no arguments are captured, causing compiler/linker scalability issues with thousands of benchmarks. BENCHMARK_NAMED provides the same func/name format but passes the function pointer directly (no lambda), consistent with the existing BENCHMARK macro. * Move BENCHMARK_NAMED test to register_benchmark_test with name assertions * Add Benjamin King to AUTHORS and CONTRIBUTORS * Fix clang-format: remove trailing spaces from BENCHMARK_NAMED macro * Fix clang-format: remove extra blank line left after test removal --------- Co-authored-by: Roman Lebedev --- AUTHORS | 1 + CONTRIBUTORS | 1 + docs/user_guide.md | 19 +++++++++++++++++++ include/benchmark/benchmark.h | 22 ++++++++++++++++++++++ test/register_benchmark_test.cc | 14 ++++++++++++++ 5 files changed, 57 insertions(+) diff --git a/AUTHORS b/AUTHORS index 11d28f7229..f3f29d6964 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,6 +12,7 @@ Albert Pretorius Alex Steele Andriy Berestovskyy Arne Beer +Benjamin King Carto Cezary Skrzyński Christian Wassermann diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 52e49cce46..447e720188 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -28,6 +28,7 @@ Alex Steele Andriy Berestovskyy Arne Beer Bátor Tallér +Benjamin King Billy Robert O'Neal III Cezary Skrzyński Chris Kennelly diff --git a/docs/user_guide.md b/docs/user_guide.md index 997737f63a..b2e6975361 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -491,6 +491,25 @@ BENCHMARK_CAPTURE(BM_takes_args, int_test, 42, 43); Note that elements of `...args` may refer to global variables. Users should avoid modifying global state inside of a benchmark. +### Naming a Benchmark Without Capturing Arguments + +If you only need to give a benchmark a custom name (without passing extra +arguments), use `BENCHMARK_NAMED(func, test_case_name)`. Unlike +`BENCHMARK_CAPTURE`, this macro does not create a lambda, which avoids +compiler and linker scalability issues when registering thousands of +benchmarks. + +```c++ +void BM_Foo(benchmark::State& state) { + for (auto _ : state) {} +} +// Registers a benchmark named "BM_Foo/my_variant" +BENCHMARK_NAMED(BM_Foo, my_variant); +``` + +Use `BENCHMARK_CAPTURE` when you need to pass extra arguments; use +`BENCHMARK_NAMED` when you only need the name. + ## Calculating Asymptotic Complexity (Big O) diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index f7d1341c8f..0963e709f9 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -1560,6 +1560,28 @@ BENCHMARK_RESTORE_COUNTER_WARNING #func "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) +// Register a benchmark named `func/test_case_name` which invokes `func` +// directly (no lambda, no extra arguments). Use this instead of +// BENCHMARK_CAPTURE when you only need a custom name and do not need to +// pass additional arguments. This avoids the lambda overhead that causes +// compiler and linker scalability issues when registering large numbers of +// benchmarks. +// +// For example: +// +// void BM_Foo(benchmark::State& state) { +// for (auto _ : state) {} +// } +// /* Registers a benchmark named "BM_Foo/my_variant" */ +// BENCHMARK_NAMED(BM_Foo, my_variant); +#define BENCHMARK_NAMED(func, test_case_name) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #func "/" #test_case_name, \ + static_cast<::benchmark::internal::Function*>(func)))) + // This will register a benchmark for a templatized function. For example: // // template diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index 3e39437a27..0ebd8f32d9 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -104,6 +104,20 @@ ReturnVal dummy3 = benchmark::RegisterBenchmark("DISABLED_BM_function_manual", DISABLED_BM_function); // No need to add cases because we don't expect them to run. +//----------------------------------------------------------------------------// +// Test BENCHMARK_NAMED: verifies name format "func/test_case_name" and that +// chaining (e.g. ->Threads()) works, without introducing a lambda. +//----------------------------------------------------------------------------// +void BM_named(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK_NAMED(BM_named, variant_a); +BENCHMARK_NAMED(BM_named, variant_b); +BENCHMARK_NAMED(BM_named, variant_c)->Threads(2); +ADD_CASES({"BM_named/variant_a"}, {"BM_named/variant_b"}, + {"BM_named/variant_c/threads:2"}); + //----------------------------------------------------------------------------// // Test RegisterBenchmark with different callable types //----------------------------------------------------------------------------// From 5c76a26e4e80c5809fd26e5b9f7bc02e704cd793 Mon Sep 17 00:00:00 2001 From: Ben King <126735454+5kng@users.noreply.github.com> Date: Sat, 28 Feb 2026 09:55:08 +1100 Subject: [PATCH 472/561] cmake: cache HAVE_* results to skip feature checks on re-runs (#2137) Without caching, HAVE_${VAR} was lost between cmake runs, so the early-exit guard never fired and all feature test messages re-printed on every reconfigure. Now HAVE_${VAR} is written to the CMake cache (INTERNAL) on both success and failure. Also fix the guard to not promote a cached 0 to 1. --- cmake/CXXFeatureCheck.cmake | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake index ee5b7591e2..59ccddf135 100644 --- a/cmake/CXXFeatureCheck.cmake +++ b/cmake/CXXFeatureCheck.cmake @@ -24,8 +24,9 @@ function(cxx_feature_check FILE) string(TOUPPER ${FILE} VAR) string(TOUPPER "HAVE_${VAR}" FEATURE) if (DEFINED HAVE_${VAR}) - set(HAVE_${VAR} 1 PARENT_SCOPE) - add_definitions(-DHAVE_${VAR}) + if(HAVE_${VAR}) + add_definitions(-DHAVE_${VAR}) + endif() return() endif() @@ -67,10 +68,11 @@ function(cxx_feature_check FILE) if(COMPILE_${FEATURE}) if(DEFINED RUN_${FEATURE} AND RUN_${FEATURE} EQUAL 0) message(STATUS "Performing Test ${FEATURE} -- success") - set(HAVE_${VAR} 1 PARENT_SCOPE) + set(HAVE_${VAR} 1 CACHE INTERNAL "") add_definitions(-DHAVE_${VAR}) else() message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run") + set(HAVE_${VAR} 0 CACHE INTERNAL "") endif() else() if(CXXFEATURECHECK_DEBUG) @@ -78,5 +80,6 @@ function(cxx_feature_check FILE) else() message(STATUS "Performing Test ${FEATURE} -- failed to compile") endif() + set(HAVE_${VAR} 0 CACHE INTERNAL "") endif() endfunction() From 4ca840dcf8cb45d1b870990e9c652c5cca370008 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:36:29 +0000 Subject: [PATCH 473/561] Bump astral-sh/setup-uv from 7.3.0 to 7.3.1 (#2136) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.3.0 to 7.3.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/eac588ad8def6316056a12d4907a9d4d84ff7a3b...5a095e7a2014a4212f075830d4f7277575a9d098) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index facd162d4e..7d56c28246 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 + uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 6f5593cfc6..5d3f252445 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 + uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e # v3.3.1 From b8ea42b2deb6d987c77fcc94493af968f0d686b4 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 4 Mar 2026 08:33:14 +0000 Subject: [PATCH 474/561] multiple fixes to avoid Windows x64 crashes (#2139) * fix: cast size_t widths to int for variadic printer to avoid Windows x64 crashes * extend minimum time as Windows can have a coarse timer * vsnprintf can consume va_list so we need to copy it to avoid UB * extend longer test runtime to other problematic tests --- src/colorprint.cc | 5 ++++- src/console_reporter.cc | 6 +++--- src/string_util.cc | 5 ++++- test/CMakeLists.txt | 6 +++--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/colorprint.cc b/src/colorprint.cc index c90232f20f..b7a6346442 100644 --- a/src/colorprint.cc +++ b/src/colorprint.cc @@ -105,7 +105,10 @@ std::string FormatString(const char* msg, va_list args) { // we did not provide a long enough buffer on our first attempt. size = static_cast(ret) + 1; // + 1 for the null byte std::unique_ptr buff(new char[size]); - ret = vsnprintf(buff.get(), size, msg, args); + va_list args_cp2; + va_copy(args_cp2, args); + ret = vsnprintf(buff.get(), size, msg, args_cp2); + va_end(args_cp2); BM_CHECK(ret > 0 && (static_cast(ret)) < size); return buff.get(); } diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 6db6788f94..a7cde4e9b2 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -137,7 +137,7 @@ void ConsoleReporter::PrintRunData(const Run& result) { : IgnoreColorPrint; auto name_color = (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN; - printer(Out, name_color, "%-*s ", name_field_width_, + printer(Out, name_color, "%-*s ", static_cast(name_field_width_), result.benchmark_name().c_str()); if (internal::SkippedWithError == result.skipped) { @@ -196,8 +196,8 @@ void ConsoleReporter::PrintRunData(const Run& result) { } } if ((output_options_ & OO_Tabular) != 0) { - printer(Out, COLOR_DEFAULT, " %*s%s", cNameLen - strlen(unit), s.c_str(), - unit); + printer(Out, COLOR_DEFAULT, " %*s%s", + static_cast(cNameLen - strlen(unit)), s.c_str(), unit); } else { printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(), unit); } diff --git a/src/string_util.cc b/src/string_util.cc index 9c5df3ba25..aa36cf949a 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -142,7 +142,10 @@ std::string StrFormatImp(const char* msg, va_list args) { auto buff_ptr = std::unique_ptr(new char[size]); // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation // in the android-ndk - vsnprintf(buff_ptr.get(), size, msg, args); + va_list args_cp2; + va_copy(args_cp2, args); + vsnprintf(buff_ptr.get(), size, msg, args_cp2); + va_end(args_cp2); return std::string(buff_ptr.get()); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a1a1a968f..2917efa513 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -184,10 +184,10 @@ compile_output_test(templated_fixture_method_test) benchmark_add_test(NAME templated_fixture_method_test COMMAND templated_fixture_method_test --benchmark_min_time=0.01s) compile_output_test(user_counters_test) -benchmark_add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.2s) compile_output_test(user_counters_threads_test) -benchmark_add_test(NAME user_counters_threads_test COMMAND user_counters_threads_test --benchmark_min_time=0.01s) +benchmark_add_test(NAME user_counters_threads_test COMMAND user_counters_threads_test --benchmark_min_time=0.2s) compile_output_test(perf_counters_test) benchmark_add_test(NAME perf_counters_test COMMAND perf_counters_test --benchmark_min_time=0.01s --benchmark_perf_counters=CYCLES,INSTRUCTIONS) @@ -205,7 +205,7 @@ compile_output_test(display_aggregates_only_test) benchmark_add_test(NAME display_aggregates_only_test COMMAND display_aggregates_only_test --benchmark_min_time=0.01s) compile_output_test(user_counters_tabular_test) -benchmark_add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.01s) +benchmark_add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.2s) compile_output_test(user_counters_thousands_test) benchmark_add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test --benchmark_min_time=0.01s) From 6daf2dff6f7018187309d480867e7ea60c8ba917 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:53:50 +0000 Subject: [PATCH 475/561] Refactor/modularize headers (#2140) * Split the benchmark monolithic header * src uses modular headers * updated tests to use split headers * clang-format * clang-format mistake * fix exports * suppress warnings on msvc * fixing double pops and some more missing exports --- BUILD.bazel | 22 + README.md | 3 +- include/benchmark/benchmark.h | 2108 +---------------- include/benchmark/benchmark_api.h | 292 +++ include/benchmark/counter.h | 80 + include/benchmark/macros.h | 136 ++ include/benchmark/managers.h | 66 + include/benchmark/registration.h | 258 ++ include/benchmark/reporter.h | 238 ++ include/benchmark/state.h | 265 +++ include/benchmark/statistics.h | 65 + include/benchmark/sysinfo.h | 71 + include/benchmark/types.h | 50 + include/benchmark/utils.h | 152 ++ src/benchmark.cc | 7 +- src/benchmark_api_internal.h | 4 +- src/benchmark_main.cc | 3 +- src/benchmark_name.cc | 3 +- src/benchmark_register.cc | 6 +- src/benchmark_runner.cc | 6 +- src/complexity.cc | 4 +- src/complexity.h | 3 +- src/console_reporter.cc | 4 +- src/counter.h | 11 +- src/csv_reporter.cc | 3 +- src/cycleclock.h | 2 +- src/json_reporter.cc | 5 +- src/perf_counters.h | 5 +- src/reporter.cc | 23 +- src/statistics.cc | 4 +- src/statistics.h | 3 +- src/string_util.cc | 2 +- src/string_util.h | 2 +- src/sysinfo.cc | 4 +- src/thread_manager.h | 4 +- test/args_product_test.cc | 5 +- test/basic_test.cc | 5 +- test/benchmark_gtest.cc | 6 +- test/benchmark_min_time_flag_iters_test.cc | 5 +- test/benchmark_min_time_flag_time_test.cc | 5 +- test/benchmark_name_gtest.cc | 2 +- test/benchmark_random_interleaving_gtest.cc | 5 +- ...benchmark_setup_teardown_cb_types_gtest.cc | 5 +- test/benchmark_setup_teardown_test.cc | 4 +- test/benchmark_test.cc | 6 +- test/clobber_memory_assembly_test.cc | 3 +- test/complexity_test.cc | 7 +- test/cxx11_test.cc | 2 +- test/diagnostics_test.cc | 5 +- test/display_aggregates_only_test.cc | 4 +- test/donotoptimize_assembly_test.cc | 3 +- test/donotoptimize_test.cc | 3 +- test/filter_test.cc | 5 +- test/fixture_test.cc | 4 +- test/internal_threading_test.cc | 5 +- test/link_main_test.cc | 4 +- test/locale_impermeability_test.cc | 4 +- test/manual_threading_test.cc | 5 +- test/map_test.cc | 5 +- test/memory_manager_test.cc | 6 +- test/memory_results_gtest.cc | 5 +- test/multiple_ranges_test.cc | 5 +- test/options_test.cc | 5 +- test/output_test.h | 2 +- test/overload_test.cc | 4 +- test/perf_counters_test.cc | 5 +- test/profiler_manager_gtest.cc | 5 +- test/profiler_manager_iterations_test.cc | 6 +- test/profiler_manager_test.cc | 6 +- test/register_benchmark_test.cc | 5 +- test/repetitions_test.cc | 4 +- test/report_aggregates_only_test.cc | 4 +- test/reporter_output_test.cc | 8 +- test/skip_with_error_test.cc | 6 +- test/spec_arg_test.cc | 5 +- test/spec_arg_verbosity_test.cc | 4 +- test/state_assembly_test.cc | 3 +- test/templated_fixture_method_test.cc | 4 +- test/templated_fixture_test.cc | 4 +- test/time_unit_gtest.cc | 3 +- test/user_counters_tabular_test.cc | 6 +- test/user_counters_test.cc | 6 +- test/user_counters_thousands_test.cc | 5 +- test/user_counters_threads_test.cc | 5 +- 84 files changed, 1957 insertions(+), 2185 deletions(-) create mode 100644 include/benchmark/benchmark_api.h create mode 100644 include/benchmark/counter.h create mode 100644 include/benchmark/macros.h create mode 100644 include/benchmark/managers.h create mode 100644 include/benchmark/registration.h create mode 100644 include/benchmark/reporter.h create mode 100644 include/benchmark/state.h create mode 100644 include/benchmark/statistics.h create mode 100644 include/benchmark/sysinfo.h create mode 100644 include/benchmark/types.h create mode 100644 include/benchmark/utils.h diff --git a/BUILD.bazel b/BUILD.bazel index 993b261204..8cad9d6ce3 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -49,7 +49,18 @@ cc_library( ), hdrs = [ "include/benchmark/benchmark.h", + "include/benchmark/benchmark_api.h", + "include/benchmark/counter.h", "include/benchmark/export.h", + "include/benchmark/macros.h", + "include/benchmark/managers.h", + "include/benchmark/registration.h", + "include/benchmark/reporter.h", + "include/benchmark/state.h", + "include/benchmark/statistics.h", + "include/benchmark/sysinfo.h", + "include/benchmark/types.h", + "include/benchmark/utils.h", ], copts = select({ ":windows": MSVC_COPTS, @@ -89,7 +100,18 @@ cc_library( srcs = ["src/benchmark_main.cc"], hdrs = [ "include/benchmark/benchmark.h", + "include/benchmark/benchmark_api.h", + "include/benchmark/counter.h", "include/benchmark/export.h", + "include/benchmark/macros.h", + "include/benchmark/managers.h", + "include/benchmark/registration.h", + "include/benchmark/reporter.h", + "include/benchmark/state.h", + "include/benchmark/statistics.h", + "include/benchmark/sysinfo.h", + "include/benchmark/types.h", + "include/benchmark/utils.h", ], includes = ["include"], visibility = ["//visibility:public"], diff --git a/README.md b/README.md index 1d4470e8ed..db99409333 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ A library to benchmark code snippets, similar to unit tests. Example: ```c++ -#include +#include +#include static void BM_SomeFunction(benchmark::State& state) { // Perform setup here diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h index 0963e709f9..e065db35cf 100644 --- a/include/benchmark/benchmark.h +++ b/include/benchmark/benchmark.h @@ -12,2105 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Support for registering benchmarks for functions. - -/* Example usage: -// Define a function that executes the code to be measured a -// specified number of times: -static void BM_StringCreation(benchmark::State& state) { - for (auto _ : state) - std::string empty_string; -} - -// Register the function as a benchmark -BENCHMARK(BM_StringCreation); - -// Define another benchmark -static void BM_StringCopy(benchmark::State& state) { - std::string x = "hello"; - for (auto _ : state) - std::string copy(x); -} -BENCHMARK(BM_StringCopy); - -// Augment the main() program to invoke benchmarks if specified -// via the --benchmark_filter command line flag. E.g., -// my_unittest --benchmark_filter=all -// my_unittest --benchmark_filter=BM_StringCreation -// my_unittest --benchmark_filter=String -// my_unittest --benchmark_filter='Copy|Creation' -int main(int argc, char** argv) { - benchmark::MaybeReenterWithoutASLR(argc, argv); - benchmark::Initialize(&argc, argv); - benchmark::RunSpecifiedBenchmarks(); - benchmark::Shutdown(); - return 0; -} - -// Sometimes a family of microbenchmarks can be implemented with -// just one routine that takes an extra argument to specify which -// one of the family of benchmarks to run. For example, the following -// code defines a family of microbenchmarks for measuring the speed -// of memcpy() calls of different lengths: - -static void BM_memcpy(benchmark::State& state) { - char* src = new char[state.range(0)]; char* dst = new char[state.range(0)]; - memset(src, 'x', state.range(0)); - for (auto _ : state) - memcpy(dst, src, state.range(0)); - state.SetBytesProcessed(state.iterations() * state.range(0)); - delete[] src; delete[] dst; -} -BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); - -// The preceding code is quite repetitive, and can be replaced with the -// following short-hand. The following invocation will pick a few -// appropriate arguments in the specified range and will generate a -// microbenchmark for each such argument. -BENCHMARK(BM_memcpy)->Range(8, 8<<10); - -// You might have a microbenchmark that depends on two inputs. For -// example, the following code defines a family of microbenchmarks for -// measuring the speed of set insertion. -static void BM_SetInsert(benchmark::State& state) { - set data; - for (auto _ : state) { - state.PauseTiming(); - data = ConstructRandomSet(state.range(0)); - state.ResumeTiming(); - for (int j = 0; j < state.range(1); ++j) - data.insert(RandomNumber()); - } -} -BENCHMARK(BM_SetInsert) - ->Args({1<<10, 128}) - ->Args({2<<10, 128}) - ->Args({4<<10, 128}) - ->Args({8<<10, 128}) - ->Args({1<<10, 512}) - ->Args({2<<10, 512}) - ->Args({4<<10, 512}) - ->Args({8<<10, 512}); - -// The preceding code is quite repetitive, and can be replaced with -// the following short-hand. The following macro will pick a few -// appropriate arguments in the product of the two specified ranges -// and will generate a microbenchmark for each such pair. -BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}}); - -// For more complex patterns of inputs, passing a custom function -// to Apply allows programmatic specification of an -// arbitrary set of arguments to run the microbenchmark on. -// The following example enumerates a dense range on -// one parameter, and a sparse range on the second. -static void CustomArguments(benchmark::Benchmark* b) { - for (int i = 0; i <= 10; ++i) - for (int j = 32; j <= 1024*1024; j *= 8) - b->Args({i, j}); -} -BENCHMARK(BM_SetInsert)->Apply(CustomArguments); - -// Templated microbenchmarks work the same way: -// Produce then consume 'size' messages 'iters' times -// Measures throughput in the absence of multiprogramming. -template int BM_Sequential(benchmark::State& state) { - Q q; - typename Q::value_type v; - for (auto _ : state) { - for (int i = state.range(0); i--; ) - q.push(v); - for (int e = state.range(0); e--; ) - q.Wait(&v); - } - // actually messages, not bytes: - state.SetBytesProcessed(state.iterations() * state.range(0)); -} -BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); - -Use `Benchmark::MinTime(double t)` to set the minimum time used to run the -benchmark. This option overrides the `benchmark_min_time` flag. - -void BM_test(benchmark::State& state) { - ... body ... -} -BENCHMARK(BM_test)->MinTime(2.0); // Run for at least 2 seconds. - -In a multithreaded test, it is guaranteed that none of the threads will start -until all have reached the loop start, and all will have finished before any -thread exits the loop body. As such, any global setup or teardown you want to -do can be wrapped in a check against the thread index: - -static void BM_MultiThreaded(benchmark::State& state) { - if (state.thread_index() == 0) { - // Setup code here. - } - for (auto _ : state) { - // Run the test as normal. - } - if (state.thread_index() == 0) { - // Teardown code here. - } -} -BENCHMARK(BM_MultiThreaded)->Threads(4); - - -If a benchmark runs a few milliseconds it may be hard to visually compare the -measured times, since the output data is given in nanoseconds per default. In -order to manually set the time unit, you can specify it manually: - -BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); -*/ - #ifndef BENCHMARK_BENCHMARK_H_ #define BENCHMARK_BENCHMARK_H_ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "benchmark/export.h" - -#if defined(_MSC_VER) -#include // for _ReadWriteBarrier -#endif - -#define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - TypeName& operator=(const TypeName&) = delete - -#ifdef BENCHMARK_HAS_CXX17 -#define BENCHMARK_UNUSED [[maybe_unused]] -#elif defined(__GNUC__) || defined(__clang__) -#define BENCHMARK_UNUSED __attribute__((unused)) -#else -#define BENCHMARK_UNUSED -#endif - -// Used to annotate functions, methods and classes so they -// are not optimized by the compiler. Useful for tests -// where you expect loops to stay in place churning cycles -#if defined(__clang__) -#define BENCHMARK_DONT_OPTIMIZE __attribute__((optnone)) -#elif defined(__GNUC__) || defined(__GNUG__) -#define BENCHMARK_DONT_OPTIMIZE __attribute__((optimize(0))) -#else -// MSVC & Intel do not have a no-optimize attribute, only line pragmas -#define BENCHMARK_DONT_OPTIMIZE -#endif - -#if defined(__GNUC__) || defined(__clang__) -#define BENCHMARK_ALWAYS_INLINE __attribute__((always_inline)) -#elif defined(_MSC_VER) && !defined(__clang__) -#define BENCHMARK_ALWAYS_INLINE __forceinline -#define __func__ __FUNCTION__ -#else -#define BENCHMARK_ALWAYS_INLINE -#endif - -#define BENCHMARK_INTERNAL_TOSTRING2(x) #x -#define BENCHMARK_INTERNAL_TOSTRING(x) BENCHMARK_INTERNAL_TOSTRING2(x) - -// clang-format off -#if (defined(__GNUC__) && !defined(__NVCC__) && !defined(__NVCOMPILER)) || defined(__clang__) -#define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) -#define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) -#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("GCC diagnostic pop") -#elif defined(__NVCOMPILER) -#define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) -#define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) -#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ - _Pragma("diagnostic push") \ - _Pragma("diag_suppress deprecated_entity_with_custom_message") -#define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("diagnostic pop") -#elif defined(_MSC_VER) -#define BENCHMARK_BUILTIN_EXPECT(x, y) x -#define BENCHMARK_DEPRECATED_MSG(msg) __declspec(deprecated(msg)) -#define BENCHMARK_WARNING_MSG(msg) \ - __pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING( \ - __LINE__) ") : warning note: " msg)) -#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ - __pragma(warning(push)) \ - __pragma(warning(disable : 4996)) -#define BENCHMARK_RESTORE_DEPRECATED_WARNING __pragma(warning(pop)) -#else -#define BENCHMARK_BUILTIN_EXPECT(x, y) x -#define BENCHMARK_DEPRECATED_MSG(msg) -#define BENCHMARK_WARNING_MSG(msg) \ - __pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING( \ - __LINE__) ") : warning note: " msg)) -#define BENCHMARK_DISABLE_DEPRECATED_WARNING -#define BENCHMARK_RESTORE_DEPRECATED_WARNING -#endif -// clang-format on - -#if defined(__GNUC__) && !defined(__clang__) -#define BENCHMARK_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -#if defined(__GNUC__) || __has_builtin(__builtin_unreachable) -#define BENCHMARK_UNREACHABLE() __builtin_unreachable() -#elif defined(_MSC_VER) -#define BENCHMARK_UNREACHABLE() __assume(false) -#else -#define BENCHMARK_UNREACHABLE() ((void)0) -#endif - -#if defined(__GNUC__) -// Determine the cacheline size based on architecture -#if defined(__i386__) || defined(__x86_64__) -#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 -#elif defined(__powerpc64__) -#define BENCHMARK_INTERNAL_CACHELINE_SIZE 128 -#elif defined(__aarch64__) -#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 -#elif defined(__arm__) -// Cache line sizes for ARM: These values are not strictly correct since -// cache line sizes depend on implementations, not architectures. There -// are even implementations with cache line sizes configurable at boot -// time. -#if defined(__ARM_ARCH_5T__) -#define BENCHMARK_INTERNAL_CACHELINE_SIZE 32 -#elif defined(__ARM_ARCH_7A__) -#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 -#endif // ARM_ARCH -#endif // arches -#endif // __GNUC__ - -#ifndef BENCHMARK_INTERNAL_CACHELINE_SIZE -// A reasonable default guess. Note that overestimates tend to waste more -// space, while underestimates tend to waste more time. -#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 -#endif - -#if defined(__GNUC__) -// Indicates that the declared object be cache aligned using -// `BENCHMARK_INTERNAL_CACHELINE_SIZE` (see above). -#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED \ - __attribute__((aligned(BENCHMARK_INTERNAL_CACHELINE_SIZE))) -#elif defined(_MSC_VER) -#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED \ - __declspec(align(BENCHMARK_INTERNAL_CACHELINE_SIZE)) -#else -#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED -#endif - -#if defined(_MSC_VER) -#pragma warning(push) -// C4251: needs to have dll-interface to be used by clients of class -#pragma warning(disable : 4251) -#endif // _MSC_VER_ - -namespace benchmark { - -namespace internal { -#if (__cplusplus < 201402L || (defined(_MSC_VER) && _MSVC_LANG < 201402L)) -template -std::unique_ptr make_unique(Args&&... args) { - return std::unique_ptr(new T(std::forward(args)...)); -} -#else -using ::std::make_unique; -#endif -} // namespace internal - -class BenchmarkReporter; -class State; - -using IterationCount = int64_t; - -// Define alias of Setup/Teardown callback function type -using callback_function = std::function; - -// Default number of minimum benchmark running time in seconds. -const char kDefaultMinTimeStr[] = "0.5s"; - -BENCHMARK_EXPORT void MaybeReenterWithoutASLR(int, char**); - -// Returns the version of the library. -BENCHMARK_EXPORT std::string GetBenchmarkVersion(); - -BENCHMARK_EXPORT void PrintDefaultHelp(); - -BENCHMARK_EXPORT void Initialize(int* argc, char** argv, - void (*HelperPrintf)() = PrintDefaultHelp); -BENCHMARK_EXPORT void Shutdown(); - -// Report to stdout all arguments in 'argv' as unrecognized except the first. -// Returns true there is at least on unrecognized argument (i.e. 'argc' > 1). -BENCHMARK_EXPORT bool ReportUnrecognizedArguments(int argc, char** argv); - -// Returns the current value of --benchmark_filter. -BENCHMARK_EXPORT std::string GetBenchmarkFilter(); - -// Sets a new value to --benchmark_filter. (This will override this flag's -// current value). -// Should be called after `benchmark::Initialize()`, as -// `benchmark::Initialize()` will override the flag's value. -BENCHMARK_EXPORT void SetBenchmarkFilter(std::string value); - -// Returns the current value of --v (command line value for verbosity). -BENCHMARK_EXPORT int32_t GetBenchmarkVerbosity(); - -// Creates a default display reporter. Used by the library when no display -// reporter is provided, but also made available for external use in case a -// custom reporter should respect the `--benchmark_format` flag as a fallback -BENCHMARK_EXPORT BenchmarkReporter* CreateDefaultDisplayReporter(); - -// Generate a list of benchmarks matching the specified --benchmark_filter flag -// and if --benchmark_list_tests is specified return after printing the name -// of each matching benchmark. Otherwise run each matching benchmark and -// report the results. -// -// spec : Specify the benchmarks to run. If users do not specify this arg, -// then the value of FLAGS_benchmark_filter -// will be used. -// -// The second and third overload use the specified 'display_reporter' and -// 'file_reporter' respectively. 'file_reporter' will write to the file -// specified -// by '--benchmark_out'. If '--benchmark_out' is not given the -// 'file_reporter' is ignored. -// -// RETURNS: The number of matching benchmarks. -BENCHMARK_EXPORT size_t RunSpecifiedBenchmarks(); -BENCHMARK_EXPORT size_t RunSpecifiedBenchmarks(std::string spec); - -BENCHMARK_EXPORT size_t -RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter); -BENCHMARK_EXPORT size_t -RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, std::string spec); - -BENCHMARK_EXPORT size_t RunSpecifiedBenchmarks( - BenchmarkReporter* display_reporter, BenchmarkReporter* file_reporter); -BENCHMARK_EXPORT size_t -RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, - BenchmarkReporter* file_reporter, std::string spec); - -// TimeUnit is passed to a benchmark in order to specify the order of magnitude -// for the measured time. -enum TimeUnit { kNanosecond, kMicrosecond, kMillisecond, kSecond }; - -BENCHMARK_EXPORT TimeUnit GetDefaultTimeUnit(); - -// Sets the default time unit the benchmarks use -// Has to be called before the benchmark loop to take effect -BENCHMARK_EXPORT void SetDefaultTimeUnit(TimeUnit unit); - -// If a MemoryManager is registered (via RegisterMemoryManager()), -// it can be used to collect and report allocation metrics for a run of the -// benchmark. -class MemoryManager { - public: - static constexpr int64_t TombstoneValue = std::numeric_limits::max(); - - struct Result { - Result() - : num_allocs(0), - max_bytes_used(0), - total_allocated_bytes(TombstoneValue), - net_heap_growth(TombstoneValue), - memory_iterations(0) {} - - // The number of allocations made in total between Start and Stop. - int64_t num_allocs; - - // The peak memory use between Start and Stop. - int64_t max_bytes_used; - - // The total memory allocated, in bytes, between Start and Stop. - // Init'ed to TombstoneValue if metric not available. - int64_t total_allocated_bytes; - - // The net changes in memory, in bytes, between Start and Stop. - // ie., total_allocated_bytes - total_deallocated_bytes. - // Init'ed to TombstoneValue if metric not available. - int64_t net_heap_growth; - - IterationCount memory_iterations; - }; - - virtual ~MemoryManager() {} - - // Implement this to start recording allocation information. - virtual void Start() = 0; - - // Implement this to stop recording and fill out the given Result structure. - virtual void Stop(Result& result) = 0; -}; - -// Register a MemoryManager instance that will be used to collect and report -// allocation measurements for benchmark runs. -BENCHMARK_EXPORT -void RegisterMemoryManager(MemoryManager* memory_manager); - -// If a ProfilerManager is registered (via RegisterProfilerManager()), the -// benchmark will be run an additional time under the profiler to collect and -// report profile metrics for the run of the benchmark. -class ProfilerManager { - public: - virtual ~ProfilerManager() {} - - // This is called after `Setup()` code and right before the benchmark is run. - virtual void AfterSetupStart() = 0; - - // This is called before `Teardown()` code and right after the benchmark - // completes. - virtual void BeforeTeardownStop() = 0; -}; - -// Register a ProfilerManager instance that will be used to collect and report -// profile measurements for benchmark runs. -BENCHMARK_EXPORT -void RegisterProfilerManager(ProfilerManager* profiler_manager); - -// Add a key-value pair to output as part of the context stanza in the report. -BENCHMARK_EXPORT -void AddCustomContext(std::string key, std::string value); - -class Benchmark; - -namespace internal { -class BenchmarkImp; -class BenchmarkFamilies; - -BENCHMARK_EXPORT std::map*& GetGlobalContext(); - -BENCHMARK_EXPORT -void UseCharPointer(char const volatile*); - -// Take ownership of the pointer and register the benchmark. Return the -// registered benchmark. -BENCHMARK_EXPORT Benchmark* RegisterBenchmarkInternal( - std::unique_ptr); - -// Ensure that the standard streams are properly initialized in every TU. -BENCHMARK_EXPORT int InitializeStreams(); -BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); - -} // namespace internal - -#if (!defined(__GNUC__) && !defined(__clang__)) || defined(__pnacl__) || \ - defined(__EMSCRIPTEN__) -#define BENCHMARK_HAS_NO_INLINE_ASSEMBLY -#endif - -// Force the compiler to flush pending writes to global memory. Acts as an -// effective read/write barrier -inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { - std::atomic_signal_fence(std::memory_order_acq_rel); -} - -// The DoNotOptimize(...) function can be used to prevent a value or -// expression from being optimized away by the compiler. This function is -// intended to add little to no overhead. -// See: https://youtu.be/nXaxk27zwlk?t=2441 -#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY -#if !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) -template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { - asm volatile("" : : "r,m"(value) : "memory"); -} - -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { -#if defined(__clang__) - asm volatile("" : "+r,m"(value) : : "memory"); -#else - asm volatile("" : "+m,r"(value) : : "memory"); -#endif -} - -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { -#if defined(__clang__) - asm volatile("" : "+r,m"(value) : : "memory"); -#else - asm volatile("" : "+m,r"(value) : : "memory"); -#endif -} -// !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) -#elif (__GNUC__ >= 5) -// Workaround for a bug with full argument copy overhead with GCC. -// See: #1340 and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105519 -template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") -inline BENCHMARK_ALWAYS_INLINE - typename std::enable_if::value && - (sizeof(Tp) <= sizeof(Tp*))>::type - DoNotOptimize(Tp const& value) { - asm volatile("" : : "r,m"(value) : "memory"); -} - -template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") -inline BENCHMARK_ALWAYS_INLINE - typename std::enable_if::value || - (sizeof(Tp) > sizeof(Tp*))>::type - DoNotOptimize(Tp const& value) { - asm volatile("" : : "m"(value) : "memory"); -} - -template -inline BENCHMARK_ALWAYS_INLINE - typename std::enable_if::value && - (sizeof(Tp) <= sizeof(Tp*))>::type - DoNotOptimize(Tp& value) { - asm volatile("" : "+m,r"(value) : : "memory"); -} - -template -inline BENCHMARK_ALWAYS_INLINE - typename std::enable_if::value || - (sizeof(Tp) > sizeof(Tp*))>::type - DoNotOptimize(Tp& value) { - asm volatile("" : "+m"(value) : : "memory"); -} - -template -inline BENCHMARK_ALWAYS_INLINE - typename std::enable_if::value && - (sizeof(Tp) <= sizeof(Tp*))>::type - DoNotOptimize(Tp&& value) { - asm volatile("" : "+m,r"(value) : : "memory"); -} - -template -inline BENCHMARK_ALWAYS_INLINE - typename std::enable_if::value || - (sizeof(Tp) > sizeof(Tp*))>::type - DoNotOptimize(Tp&& value) { - asm volatile("" : "+m"(value) : : "memory"); -} -// !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) -#endif - -#elif defined(_MSC_VER) -template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { - internal::UseCharPointer(&reinterpret_cast(value)); - _ReadWriteBarrier(); -} - -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { - internal::UseCharPointer(&reinterpret_cast(value)); - _ReadWriteBarrier(); -} - -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { - internal::UseCharPointer(&reinterpret_cast(value)); - _ReadWriteBarrier(); -} -#else -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { - internal::UseCharPointer(&reinterpret_cast(value)); -} -// FIXME Add ClobberMemory() for non-gnu and non-msvc compilers, before C++11. -#endif - -// This class is used for user-defined counters. -class Counter { - public: - enum Flags { - kDefaults = 0, - // Mark the counter as a rate. It will be presented divided - // by the duration of the benchmark. - kIsRate = 1 << 0, - // Mark the counter as a thread-average quantity. It will be - // presented divided by the number of threads. - kAvgThreads = 1 << 1, - // Mark the counter as a thread-average rate. See above. - kAvgThreadsRate = kIsRate | kAvgThreads, - // Mark the counter as a constant value, valid/same for *every* iteration. - // When reporting, it will be *multiplied* by the iteration count. - kIsIterationInvariant = 1 << 2, - // Mark the counter as a constant rate. - // When reporting, it will be *multiplied* by the iteration count - // and then divided by the duration of the benchmark. - kIsIterationInvariantRate = kIsRate | kIsIterationInvariant, - // Mark the counter as a iteration-average quantity. - // It will be presented divided by the number of iterations. - kAvgIterations = 1 << 3, - // Mark the counter as a iteration-average rate. See above. - kAvgIterationsRate = kIsRate | kAvgIterations, - - // In the end, invert the result. This is always done last! - kInvert = 1 << 31 - }; - - enum OneK { - // 1'000 items per 1k - kIs1000 = 1000, - // 1'024 items per 1k - kIs1024 = 1024 - }; - - double value; - Flags flags; - OneK oneK; - - BENCHMARK_ALWAYS_INLINE - Counter(double v = 0., Flags f = kDefaults, OneK k = kIs1000) - : value(v), flags(f), oneK(k) {} - - BENCHMARK_ALWAYS_INLINE operator double const&() const { return value; } - BENCHMARK_ALWAYS_INLINE operator double&() { return value; } -}; - -// A helper for user code to create unforeseen combinations of Flags, without -// having to do this cast manually each time, or providing this operator. -Counter::Flags inline operator|(const Counter::Flags& LHS, - const Counter::Flags& RHS) { - return static_cast(static_cast(LHS) | - static_cast(RHS)); -} - -// This is the container for the user-defined counters. -typedef std::map UserCounters; - -// BigO is passed to a benchmark in order to specify the asymptotic -// computational -// complexity for the benchmark. In case oAuto is selected, complexity will be -// calculated automatically to the best fit. -enum BigO { oNone, o1, oN, oNSquared, oNCubed, oLogN, oNLogN, oAuto, oLambda }; - -typedef int64_t ComplexityN; - -enum StatisticUnit { kTime, kPercentage }; - -// BigOFunc is passed to a benchmark in order to specify the asymptotic -// computational complexity for the benchmark. -typedef double(BigOFunc)(ComplexityN); - -// StatisticsFunc is passed to a benchmark in order to compute some descriptive -// statistics over all the measurements of some type -typedef double(StatisticsFunc)(const std::vector&); - -namespace internal { -struct Statistics { - std::string name_; - StatisticsFunc* compute_; - StatisticUnit unit_; - - Statistics(const std::string& name, StatisticsFunc* compute, - StatisticUnit unit = kTime) - : name_(name), compute_(compute), unit_(unit) {} -}; - -class BenchmarkInstance; -class ThreadTimer; -class ThreadManager; -class PerfCountersMeasurement; - -enum AggregationReportMode : unsigned { - // The mode has not been manually specified - ARM_Unspecified = 0, - // The mode is user-specified. - // This may or may not be set when the following bit-flags are set. - ARM_Default = 1U << 0U, - // File reporter should only output aggregates. - ARM_FileReportAggregatesOnly = 1U << 1U, - // Display reporter should only output aggregates - ARM_DisplayReportAggregatesOnly = 1U << 2U, - // Both reporters should only display aggregates. - ARM_ReportAggregatesOnly = - ARM_FileReportAggregatesOnly | ARM_DisplayReportAggregatesOnly -}; - -enum Skipped : unsigned { - NotSkipped = 0, - SkippedWithMessage, - SkippedWithError -}; - -} // namespace internal - -#if defined(_MSC_VER) -#pragma warning(push) -// C4324: 'benchmark::State': structure was padded due to alignment specifier -#pragma warning(disable : 4324) -#endif // _MSC_VER_ -// State is passed to a running Benchmark and contains state for the -// benchmark to use. -class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { - public: - struct StateIterator; - friend struct StateIterator; - - // Returns iterators used to run each iteration of a benchmark using a - // C++11 ranged-based for loop. These functions should not be called directly. - // - // REQUIRES: The benchmark has not started running yet. Neither begin nor end - // have been called previously. - // - // NOTE: KeepRunning may not be used after calling either of these functions. - inline BENCHMARK_ALWAYS_INLINE StateIterator begin(); - inline BENCHMARK_ALWAYS_INLINE StateIterator end(); - - // Returns true if the benchmark should continue through another iteration. - // NOTE: A benchmark may not return from the test until KeepRunning() has - // returned false. - inline bool KeepRunning(); - - // Returns true iff the benchmark should run n more iterations. - // REQUIRES: 'n' > 0. - // NOTE: A benchmark must not return from the test until KeepRunningBatch() - // has returned false. - // NOTE: KeepRunningBatch() may overshoot by up to 'n' iterations. - // - // Intended usage: - // while (state.KeepRunningBatch(1000)) { - // // process 1000 elements - // } - inline bool KeepRunningBatch(IterationCount n); - - // REQUIRES: timer is running and 'SkipWithMessage(...)' or - // 'SkipWithError(...)' has not been called by the current thread. - // Stop the benchmark timer. If not called, the timer will be - // automatically stopped after the last iteration of the benchmark loop. - // - // For threaded benchmarks the PauseTiming() function only pauses the timing - // for the current thread. - // - // NOTE: The "real time" measurement is per-thread. If different threads - // report different measurements the largest one is reported. - // - // NOTE: PauseTiming()/ResumeTiming() are relatively - // heavyweight, and so their use should generally be avoided - // within each benchmark iteration, if possible. - void PauseTiming(); - - // REQUIRES: timer is not running and 'SkipWithMessage(...)' or - // 'SkipWithError(...)' has not been called by the current thread. - // Start the benchmark timer. The timer is NOT running on entrance to the - // benchmark function. It begins running after control flow enters the - // benchmark loop. - // - // NOTE: PauseTiming()/ResumeTiming() are relatively - // heavyweight, and so their use should generally be avoided - // within each benchmark iteration, if possible. - void ResumeTiming(); - - // REQUIRES: 'SkipWithMessage(...)' or 'SkipWithError(...)' has not been - // called previously by the current thread. - // Report the benchmark as resulting in being skipped with the specified - // 'msg'. - // After this call the user may explicitly 'return' from the benchmark. - // - // If the ranged-for style of benchmark loop is used, the user must explicitly - // break from the loop, otherwise all future iterations will be run. - // If the 'KeepRunning()' loop is used the current thread will automatically - // exit the loop at the end of the current iteration. - // - // For threaded benchmarks only the current thread stops executing and future - // calls to `KeepRunning()` will block until all threads have completed - // the `KeepRunning()` loop. If multiple threads report being skipped only the - // first skip message is used. - // - // NOTE: Calling 'SkipWithMessage(...)' does not cause the benchmark to exit - // the current scope immediately. If the function is called from within - // the 'KeepRunning()' loop the current iteration will finish. It is the users - // responsibility to exit the scope as needed. - void SkipWithMessage(const std::string& msg); - - // REQUIRES: 'SkipWithMessage(...)' or 'SkipWithError(...)' has not been - // called previously by the current thread. - // Report the benchmark as resulting in an error with the specified 'msg'. - // After this call the user may explicitly 'return' from the benchmark. - // - // If the ranged-for style of benchmark loop is used, the user must explicitly - // break from the loop, otherwise all future iterations will be run. - // If the 'KeepRunning()' loop is used the current thread will automatically - // exit the loop at the end of the current iteration. - // - // For threaded benchmarks only the current thread stops executing and future - // calls to `KeepRunning()` will block until all threads have completed - // the `KeepRunning()` loop. If multiple threads report an error only the - // first error message is used. - // - // NOTE: Calling 'SkipWithError(...)' does not cause the benchmark to exit - // the current scope immediately. If the function is called from within - // the 'KeepRunning()' loop the current iteration will finish. It is the users - // responsibility to exit the scope as needed. - void SkipWithError(const std::string& msg); - - // Returns true if 'SkipWithMessage(...)' or 'SkipWithError(...)' was called. - bool skipped() const { return internal::NotSkipped != skipped_; } - - // Returns true if an error has been reported with 'SkipWithError(...)'. - bool error_occurred() const { return internal::SkippedWithError == skipped_; } - - // REQUIRES: called exactly once per iteration of the benchmarking loop. - // Set the manually measured time for this benchmark iteration, which - // is used instead of automatically measured time if UseManualTime() was - // specified. - // - // For threaded benchmarks the final value will be set to the largest - // reported values. - void SetIterationTime(double seconds); - - // Set the number of bytes processed by the current benchmark - // execution. This routine is typically called once at the end of a - // throughput oriented benchmark. - // - // REQUIRES: a benchmark has exited its benchmarking loop. - BENCHMARK_ALWAYS_INLINE - void SetBytesProcessed(int64_t bytes) { - counters["bytes_per_second"] = - Counter(static_cast(bytes), Counter::kIsRate, Counter::kIs1024); - } - - BENCHMARK_ALWAYS_INLINE - int64_t bytes_processed() const { - if (counters.find("bytes_per_second") != counters.end()) - return static_cast(counters.at("bytes_per_second")); - return 0; - } - - // If this routine is called with complexity_n > 0 and complexity report is - // requested for the - // family benchmark, then current benchmark will be part of the computation - // and complexity_n will - // represent the length of N. - BENCHMARK_ALWAYS_INLINE - void SetComplexityN(ComplexityN complexity_n) { - complexity_n_ = complexity_n; - } - - BENCHMARK_ALWAYS_INLINE - ComplexityN complexity_length_n() const { return complexity_n_; } - - // If this routine is called with items > 0, then an items/s - // label is printed on the benchmark report line for the currently - // executing benchmark. It is typically called at the end of a processing - // benchmark where a processing items/second output is desired. - // - // REQUIRES: a benchmark has exited its benchmarking loop. - BENCHMARK_ALWAYS_INLINE - void SetItemsProcessed(int64_t items) { - counters["items_per_second"] = - Counter(static_cast(items), benchmark::Counter::kIsRate); - } - - BENCHMARK_ALWAYS_INLINE - int64_t items_processed() const { - if (counters.find("items_per_second") != counters.end()) - return static_cast(counters.at("items_per_second")); - return 0; - } - - // If this routine is called, the specified label is printed at the - // end of the benchmark report line for the currently executing - // benchmark. Example: - // static void BM_Compress(benchmark::State& state) { - // ... - // double compress = input_size / output_size; - // state.SetLabel(StrFormat("compress:%.1f%%", 100.0*compression)); - // } - // Produces output that looks like: - // BM_Compress 50 50 14115038 compress:27.3% - // - // REQUIRES: a benchmark has exited its benchmarking loop. - void SetLabel(const std::string& label); - - // Range arguments for this run. CHECKs if the argument has been set. - BENCHMARK_ALWAYS_INLINE - int64_t range(std::size_t pos = 0) const { - assert(range_.size() > pos); - return range_[pos]; - } - - BENCHMARK_DEPRECATED_MSG("use 'range(0)' instead") - int64_t range_x() const { return range(0); } - - BENCHMARK_DEPRECATED_MSG("use 'range(1)' instead") - int64_t range_y() const { return range(1); } - - // Number of threads concurrently executing the benchmark. - BENCHMARK_ALWAYS_INLINE - int threads() const { return threads_; } - - // Index of the executing thread. Values from [0, threads). - BENCHMARK_ALWAYS_INLINE - int thread_index() const { return thread_index_; } - - BENCHMARK_ALWAYS_INLINE - IterationCount iterations() const { - if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) { - return 0; - } - return max_iterations - total_iterations_ + batch_leftover_; - } - - BENCHMARK_ALWAYS_INLINE - std::string name() const { return name_; } - - size_t range_size() const { return range_.size(); } - - private: - // items we expect on the first cache line (ie 64 bytes of the struct) - // When total_iterations_ is 0, KeepRunning() and friends will return false. - // May be larger than max_iterations. - IterationCount total_iterations_; - - // When using KeepRunningBatch(), batch_leftover_ holds the number of - // iterations beyond max_iters that were run. Used to track - // completed_iterations_ accurately. - IterationCount batch_leftover_; - - public: - const IterationCount max_iterations; - - private: - bool started_; - bool finished_; - internal::Skipped skipped_; - - // items we don't need on the first cache line - std::vector range_; - - ComplexityN complexity_n_; - - public: - // Container for user-defined counters. - UserCounters counters; - - private: - State(std::string name, IterationCount max_iters, - const std::vector& ranges, int thread_i, int n_threads, - internal::ThreadTimer* timer, internal::ThreadManager* manager, - internal::PerfCountersMeasurement* perf_counters_measurement, - ProfilerManager* profiler_manager); - - void StartKeepRunning(); - // Implementation of KeepRunning() and KeepRunningBatch(). - // is_batch must be true unless n is 1. - inline bool KeepRunningInternal(IterationCount n, bool is_batch); - void FinishKeepRunning(); - - const std::string name_; - const int thread_index_; - const int threads_; - - internal::ThreadTimer* const timer_; - internal::ThreadManager* const manager_; - internal::PerfCountersMeasurement* const perf_counters_measurement_; - ProfilerManager* const profiler_manager_; - - friend class internal::BenchmarkInstance; -}; -#if defined(_MSC_VER) -#pragma warning(pop) -#endif // _MSC_VER_ - -inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunning() { - return KeepRunningInternal(1, /*is_batch=*/false); -} - -inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningBatch(IterationCount n) { - return KeepRunningInternal(n, /*is_batch=*/true); -} - -inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n, - bool is_batch) { - // total_iterations_ is set to 0 by the constructor, and always set to a - // nonzero value by StartKepRunning(). - assert(n > 0); - // n must be 1 unless is_batch is true. - assert(is_batch || n == 1); - if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) { - total_iterations_ -= n; - return true; - } - if (!started_) { - StartKeepRunning(); - if (!skipped() && total_iterations_ >= n) { - total_iterations_ -= n; - return true; - } - } - // For non-batch runs, total_iterations_ must be 0 by now. - if (is_batch && total_iterations_ != 0) { - batch_leftover_ = n - total_iterations_; - total_iterations_ = 0; - return true; - } - FinishKeepRunning(); - return false; -} - -struct State::StateIterator { - struct BENCHMARK_UNUSED Value {}; - typedef std::forward_iterator_tag iterator_category; - typedef Value value_type; - typedef Value reference; - typedef Value pointer; - typedef std::ptrdiff_t difference_type; - - private: - friend class State; - BENCHMARK_ALWAYS_INLINE - StateIterator() : cached_(0), parent_() {} - - BENCHMARK_ALWAYS_INLINE - explicit StateIterator(State* st) - : cached_(st->skipped() ? 0 : st->max_iterations), parent_(st) {} - - public: - BENCHMARK_ALWAYS_INLINE - Value operator*() const { return Value(); } - - BENCHMARK_ALWAYS_INLINE - StateIterator& operator++() { - assert(cached_ > 0); - --cached_; - return *this; - } - - BENCHMARK_ALWAYS_INLINE - bool operator!=(StateIterator const&) const { - if (BENCHMARK_BUILTIN_EXPECT(cached_ != 0, true)) return true; - parent_->FinishKeepRunning(); - return false; - } - - private: - IterationCount cached_; - State* const parent_; -}; - -inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::begin() { - return StateIterator(this); -} -inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { - StartKeepRunning(); - return StateIterator(); -} - -// Base class for user-defined multi-threading -struct ThreadRunnerBase { - virtual ~ThreadRunnerBase() {} - virtual void RunThreads(const std::function& fn) = 0; -}; - -// Define alias of ThreadRunner factory function type -using threadrunner_factory = - std::function(int)>; - -// ------------------------------------------------------ -// Benchmark registration object. The BENCHMARK() macro expands into a -// Benchmark* object. Various methods can be called on this object to -// change the properties of the benchmark. Each method returns "this" so -// that multiple method calls can chained into one expression. -class BENCHMARK_EXPORT Benchmark { - public: - virtual ~Benchmark(); - - // Note: the following methods all return "this" so that multiple - // method calls can be chained together in one expression. - - // Specify the name of the benchmark - Benchmark* Name(const std::string& name); - - // Run this benchmark once with "x" as the extra argument passed - // to the function. - // REQUIRES: The function passed to the constructor must accept an arg1. - Benchmark* Arg(int64_t x); - - // Run this benchmark with the given time unit for the generated output report - Benchmark* Unit(TimeUnit unit); - - // Run this benchmark once for a number of values picked from the - // range [start..limit]. (start and limit are always picked.) - // REQUIRES: The function passed to the constructor must accept an arg1. - Benchmark* Range(int64_t start, int64_t limit); - - // Run this benchmark once for all values in the range [start..limit] with - // specific step - // REQUIRES: The function passed to the constructor must accept an arg1. - Benchmark* DenseRange(int64_t start, int64_t limit, int step = 1); - - // Run this benchmark once with "args" as the extra arguments passed - // to the function. - // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... - Benchmark* Args(const std::vector& args); - - // Equivalent to Args({x, y}) - // NOTE: This is a legacy C++03 interface provided for compatibility only. - // New code should use 'Args'. - Benchmark* ArgPair(int64_t x, int64_t y) { - std::vector args; - args.push_back(x); - args.push_back(y); - return Args(args); - } - - // Run this benchmark once for a number of values picked from the - // ranges [start..limit]. (starts and limits are always picked.) - // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... - Benchmark* Ranges(const std::vector>& ranges); - - // Run this benchmark once for each combination of values in the (cartesian) - // product of the supplied argument lists. - // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... - Benchmark* ArgsProduct(const std::vector>& arglists); - - // Equivalent to ArgNames({name}) - Benchmark* ArgName(const std::string& name); - - // Set the argument names to display in the benchmark name. If not called, - // only argument values will be shown. - Benchmark* ArgNames(const std::vector& names); - - // Equivalent to Ranges({{lo1, hi1}, {lo2, hi2}}). - // NOTE: This is a legacy C++03 interface provided for compatibility only. - // New code should use 'Ranges'. - Benchmark* RangePair(int64_t lo1, int64_t hi1, int64_t lo2, int64_t hi2) { - std::vector> ranges; - ranges.push_back(std::make_pair(lo1, hi1)); - ranges.push_back(std::make_pair(lo2, hi2)); - return Ranges(ranges); - } - - // Have "setup" and/or "teardown" invoked once for every benchmark run. - // If the benchmark is multi-threaded (will run in k threads concurrently), - // the setup callback will be be invoked exactly once (not k times) before - // each run with k threads. Time allowing (e.g. for a short benchmark), there - // may be multiple such runs per benchmark, each run with its own - // "setup"/"teardown". - // - // If the benchmark uses different size groups of threads (e.g. via - // ThreadRange), the above will be true for each size group. - // - // The callback will be passed a State object, which includes the number - // of threads, thread-index, benchmark arguments, etc. - Benchmark* Setup(callback_function&&); - Benchmark* Setup(const callback_function&); - Benchmark* Teardown(callback_function&&); - Benchmark* Teardown(const callback_function&); - - // Pass this benchmark object to *func, which can customize - // the benchmark by calling various methods like Arg, Args, - // Threads, etc. - Benchmark* Apply(const std::function&); - - // Set the range multiplier for non-dense range. If not called, the range - // multiplier kRangeMultiplier will be used. - Benchmark* RangeMultiplier(int multiplier); - - // Set the minimum amount of time to use when running this benchmark. This - // option overrides the `benchmark_min_time` flag. - // REQUIRES: `t > 0` and `Iterations` has not been called on this benchmark. - Benchmark* MinTime(double t); - - // Set the minimum amount of time to run the benchmark before taking runtimes - // of this benchmark into account. This - // option overrides the `benchmark_min_warmup_time` flag. - // REQUIRES: `t >= 0` and `Iterations` has not been called on this benchmark. - Benchmark* MinWarmUpTime(double t); - - // Specify the amount of iterations that should be run by this benchmark. - // This option overrides the `benchmark_min_time` flag. - // REQUIRES: 'n > 0' and `MinTime` has not been called on this benchmark. - // - // NOTE: This function should only be used when *exact* iteration control is - // needed and never to control or limit how long a benchmark runs, where - // `--benchmark_min_time=s` or `MinTime(...)` should be used instead. - Benchmark* Iterations(IterationCount n); - - // Specify the amount of times to repeat this benchmark. This option overrides - // the `benchmark_repetitions` flag. - // REQUIRES: `n > 0` - Benchmark* Repetitions(int n); - - // Specify if each repetition of the benchmark should be reported separately - // or if only the final statistics should be reported. If the benchmark - // is not repeated then the single result is always reported. - // Applies to *ALL* reporters (display and file). - Benchmark* ReportAggregatesOnly(bool value = true); - - // Same as ReportAggregatesOnly(), but applies to display reporter only. - Benchmark* DisplayAggregatesOnly(bool value = true); - - // By default, the CPU time is measured only for the main thread, which may - // be unrepresentative if the benchmark uses threads internally. If called, - // the total CPU time spent by all the threads will be measured instead. - // By default, only the main thread CPU time will be measured. - Benchmark* MeasureProcessCPUTime(); - - // If a particular benchmark should use the Wall clock instead of the CPU time - // (be it either the CPU time of the main thread only (default), or the - // total CPU usage of the benchmark), call this method. If called, the elapsed - // (wall) time will be used to control how many iterations are run, and in the - // printing of items/second or MB/seconds values. - // If not called, the CPU time used by the benchmark will be used. - Benchmark* UseRealTime(); - - // If a benchmark must measure time manually (e.g. if GPU execution time is - // being - // measured), call this method. If called, each benchmark iteration should - // call - // SetIterationTime(seconds) to report the measured time, which will be used - // to control how many iterations are run, and in the printing of items/second - // or MB/second values. - Benchmark* UseManualTime(); - - // Set the asymptotic computational complexity for the benchmark. If called - // the asymptotic computational complexity will be shown on the output. - Benchmark* Complexity(BigO complexity = benchmark::oAuto); - - // Set the asymptotic computational complexity for the benchmark. If called - // the asymptotic computational complexity will be shown on the output. - Benchmark* Complexity(BigOFunc* complexity); - - // Add this statistics to be computed over all the values of benchmark run - Benchmark* ComputeStatistics(const std::string& name, - StatisticsFunc* statistics, - StatisticUnit unit = kTime); - - // Support for running multiple copies of the same benchmark concurrently - // in multiple threads. This may be useful when measuring the scaling - // of some piece of code. - - // Run one instance of this benchmark concurrently in t threads. - Benchmark* Threads(int t); - - // Pick a set of values T from [min_threads,max_threads]. - // min_threads and max_threads are always included in T. Run this - // benchmark once for each value in T. The benchmark run for a - // particular value t consists of t threads running the benchmark - // function concurrently. For example, consider: - // BENCHMARK(Foo)->ThreadRange(1,16); - // This will run the following benchmarks: - // Foo in 1 thread - // Foo in 2 threads - // Foo in 4 threads - // Foo in 8 threads - // Foo in 16 threads - Benchmark* ThreadRange(int min_threads, int max_threads); - - // For each value n in the range, run this benchmark once using n threads. - // min_threads and max_threads are always included in the range. - // stride specifies the increment. E.g. DenseThreadRange(1, 8, 3) starts - // a benchmark with 1, 4, 7 and 8 threads. - Benchmark* DenseThreadRange(int min_threads, int max_threads, int stride = 1); - - // Equivalent to ThreadRange(NumCPUs(), NumCPUs()) - Benchmark* ThreadPerCpu(); - - // Sets a user-defined threadrunner (see ThreadRunnerBase) - Benchmark* ThreadRunner(threadrunner_factory&& factory); - - virtual void Run(State& state) = 0; - - TimeUnit GetTimeUnit() const; - - protected: - explicit Benchmark(const std::string& name); - void SetName(const std::string& name); - - public: - const char* GetName() const; - int ArgsCnt() const; - const char* GetArgName(int arg) const; - - private: - friend class internal::BenchmarkFamilies; - friend class internal::BenchmarkInstance; - - std::string name_; - internal::AggregationReportMode aggregation_report_mode_; - std::vector arg_names_; // Args for all benchmark runs - std::vector> args_; // Args for all benchmark runs - - TimeUnit time_unit_; - bool use_default_time_unit_; - - int range_multiplier_; - double min_time_; - double min_warmup_time_; - IterationCount iterations_; - int repetitions_; - bool measure_process_cpu_time_; - bool use_real_time_; - bool use_manual_time_; - BigO complexity_; - BigOFunc* complexity_lambda_; - std::vector statistics_; - std::vector thread_counts_; - - callback_function setup_; - callback_function teardown_; - - threadrunner_factory threadrunner_; - - BENCHMARK_DISALLOW_COPY_AND_ASSIGN(Benchmark); -}; - -namespace internal { - -// clang-format off -typedef BENCHMARK_DEPRECATED_MSG("Use ::benchmark::Benchmark instead") - ::benchmark::Benchmark Benchmark; -typedef BENCHMARK_DEPRECATED_MSG( - "Use ::benchmark::threadrunner_factory instead") - ::benchmark::threadrunner_factory threadrunner_factory; -// clang-format on - -typedef void(Function)(State&); - -} // namespace internal - -// Create and register a benchmark with the specified 'name' that invokes -// the specified functor 'fn'. -// -// RETURNS: A pointer to the registered benchmark. -Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn); - -template -Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn); - -// Remove all registered benchmarks. All pointers to previously registered -// benchmarks are invalidated. -BENCHMARK_EXPORT void ClearRegisteredBenchmarks(); - -namespace internal { -// The class used to hold all Benchmarks created from static function. -// (ie those created using the BENCHMARK(...) macros. -class BENCHMARK_EXPORT FunctionBenchmark : public benchmark::Benchmark { - public: - FunctionBenchmark(const std::string& name, Function* func) - : Benchmark(name), func_(func) {} - - void Run(State& st) override; - - private: - Function* func_; -}; - -template -class LambdaBenchmark : public benchmark::Benchmark { - public: - void Run(State& st) override { lambda_(st); } - - template - LambdaBenchmark(const std::string& name, OLambda&& lam) - : Benchmark(name), lambda_(std::forward(lam)) {} - - private: - LambdaBenchmark(LambdaBenchmark const&) = delete; - Lambda lambda_; -}; -} // namespace internal - -inline Benchmark* RegisterBenchmark(const std::string& name, - internal::Function* fn) { - return internal::RegisterBenchmarkInternal( - ::benchmark::internal::make_unique(name, - fn)); -} - -template -Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { - using BenchType = - internal::LambdaBenchmark::type>; - return internal::RegisterBenchmarkInternal( - ::benchmark::internal::make_unique(name, - std::forward(fn))); -} - -template -Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn, - Args&&... args) { - return benchmark::RegisterBenchmark( - name, [=](benchmark::State& st) { fn(st, args...); }); -} - -// The base class for all fixture tests. -class Fixture : public Benchmark { - public: - Fixture() : Benchmark("") {} - - void Run(State& st) override { - this->SetUp(st); - this->BenchmarkCase(st); - this->TearDown(st); - } - - // These will be deprecated ... - virtual void SetUp(const State&) {} - virtual void TearDown(const State&) {} - // ... In favor of these. - virtual void SetUp(State& st) { SetUp(const_cast(st)); } - virtual void TearDown(State& st) { TearDown(const_cast(st)); } - - protected: - virtual void BenchmarkCase(State&) = 0; -}; -} // namespace benchmark - -// ------------------------------------------------------ -// Macro to register benchmarks - -// clang-format off -#if defined(__clang__) -#define BENCHMARK_DISABLE_COUNTER_WARNING \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wunknown-warning-option\"") \ - _Pragma("GCC diagnostic ignored \"-Wc2y-extensions\"") -#define BENCHMARK_RESTORE_COUNTER_WARNING _Pragma("GCC diagnostic pop") -#else -#define BENCHMARK_DISABLE_COUNTER_WARNING -#define BENCHMARK_RESTORE_COUNTER_WARNING -#endif -// clang-format on - -// Check that __COUNTER__ is defined and that __COUNTER__ increases by 1 -// every time it is expanded. X + 1 == X + 0 is used in case X is defined to be -// empty. If X is empty the expression becomes (+1 == +0). -BENCHMARK_DISABLE_COUNTER_WARNING -#if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) -#define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__ -#else -#define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__ -#endif -BENCHMARK_RESTORE_COUNTER_WARNING - -// Helpers for generating unique variable names -#define BENCHMARK_PRIVATE_NAME(...) \ - BENCHMARK_PRIVATE_CONCAT(benchmark_uniq_, BENCHMARK_PRIVATE_UNIQUE_ID, \ - __VA_ARGS__) - -#define BENCHMARK_PRIVATE_CONCAT(a, b, c) BENCHMARK_PRIVATE_CONCAT2(a, b, c) -#define BENCHMARK_PRIVATE_CONCAT2(a, b, c) a##b##c -// Helper for concatenation with macro name expansion -#define BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method) \ - BaseClass##_##Method##_Benchmark - -#define BENCHMARK_PRIVATE_DECLARE(n) \ - BENCHMARK_DISABLE_COUNTER_WARNING \ - /* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \ - static ::benchmark::Benchmark const* const BENCHMARK_PRIVATE_NAME(n) \ - BENCHMARK_RESTORE_COUNTER_WARNING BENCHMARK_UNUSED - -#define BENCHMARK(...) \ - BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>( \ - #__VA_ARGS__, \ - static_cast<::benchmark::internal::Function*>(__VA_ARGS__)))) - -// Old-style macros -#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) -#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->Args({(a1), (a2)}) -#define BENCHMARK_WITH_UNIT(n, t) BENCHMARK(n)->Unit((t)) -#define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi)) -#define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ - BENCHMARK(n)->RangePair({{(l1), (h1)}, {(l2), (h2)}}) - -// Register a benchmark which invokes the function specified by `func` -// with the additional arguments specified by `...`. -// -// For example: -// -// template ` -// void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) { -// [...] -//} -// /* Registers a benchmark named "BM_takes_args/int_string_test` */ -// BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); -#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ - BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>( \ - #func "/" #test_case_name, \ - [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) - -// Register a benchmark named `func/test_case_name` which invokes `func` -// directly (no lambda, no extra arguments). Use this instead of -// BENCHMARK_CAPTURE when you only need a custom name and do not need to -// pass additional arguments. This avoids the lambda overhead that causes -// compiler and linker scalability issues when registering large numbers of -// benchmarks. -// -// For example: -// -// void BM_Foo(benchmark::State& state) { -// for (auto _ : state) {} -// } -// /* Registers a benchmark named "BM_Foo/my_variant" */ -// BENCHMARK_NAMED(BM_Foo, my_variant); -#define BENCHMARK_NAMED(func, test_case_name) \ - BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>( \ - #func "/" #test_case_name, \ - static_cast<::benchmark::internal::Function*>(func)))) - -// This will register a benchmark for a templatized function. For example: -// -// template -// void BM_Foo(int iters); -// -// BENCHMARK_TEMPLATE(BM_Foo, 1); -// -// will register BM_Foo<1> as a benchmark. -#define BENCHMARK_TEMPLATE1(n, a) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>( \ - #n "<" #a ">", \ - static_cast<::benchmark::internal::Function*>(n)))) - -#define BENCHMARK_TEMPLATE2(n, a, b) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>( \ - #n "<" #a "," #b ">", \ - static_cast<::benchmark::internal::Function*>(n)))) - -#define BENCHMARK_TEMPLATE(n, ...) \ - BENCHMARK_PRIVATE_DECLARE(n) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>( \ - #n "<" #__VA_ARGS__ ">", \ - static_cast<::benchmark::internal::Function*>(n<__VA_ARGS__>)))) - -// This will register a benchmark for a templatized function, -// with the additional arguments specified by `...`. -// -// For example: -// -// template ` -// void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) { -// [...] -//} -// /* Registers a benchmark named "BM_takes_args/int_string_test` */ -// BENCHMARK_TEMPLATE1_CAPTURE(BM_takes_args, void, int_string_test, 42, -// std::string("abc")); -#define BENCHMARK_TEMPLATE1_CAPTURE(func, a, test_case_name, ...) \ - BENCHMARK_CAPTURE(func, test_case_name, __VA_ARGS__) - -#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ - BENCHMARK_PRIVATE_DECLARE(func) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique< \ - ::benchmark::internal::FunctionBenchmark>( \ - #func "<" #a "," #b ">" \ - "/" #test_case_name, \ - [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) - -#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ - class BaseClass##_##Method##_Benchmark : public BaseClass { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "/" #Method); \ - } \ - \ - protected: \ - void BenchmarkCase(::benchmark::State&) override; \ - }; - -#define BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ - class BaseClass##_##Method##_Benchmark : public BaseClass { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "<" #a ">/" #Method); \ - } \ - \ - protected: \ - void BenchmarkCase(::benchmark::State&) override; \ - }; - -#define BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ - class BaseClass##_##Method##_Benchmark : public BaseClass { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "<" #a "," #b ">/" #Method); \ - } \ - \ - protected: \ - void BenchmarkCase(::benchmark::State&) override; \ - }; - -#define BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, ...) \ - class BaseClass##_##Method##_Benchmark : public BaseClass<__VA_ARGS__> { \ - public: \ - BaseClass##_##Method##_Benchmark() { \ - this->SetName(#BaseClass "<" #__VA_ARGS__ ">/" #Method); \ - } \ - \ - protected: \ - void BenchmarkCase(::benchmark::State&) override; \ - }; - -#define BENCHMARK_DEFINE_F(BaseClass, Method) \ - BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_TEMPLATE1_DEFINE_F(BaseClass, Method, a) \ - BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_TEMPLATE2_DEFINE_F(BaseClass, Method, a, b) \ - BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, ...) \ - BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_REGISTER_F(BaseClass, Method) \ - BENCHMARK_PRIVATE_REGISTER_F(BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)) - -#define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ - BENCHMARK_PRIVATE_DECLARE(TestName) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique())) - -#define BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ - BaseClass##_##Method##_BenchmarkTemplate - -#define BENCHMARK_TEMPLATE_METHOD_F(BaseClass, Method) \ - template \ - class BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ - : public BaseClass { \ - protected: \ - using Base = BaseClass; \ - void BenchmarkCase(::benchmark::State&) override; \ - }; \ - template \ - void BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ - BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F(BaseClass, Method, \ - UniqueName, ...) \ - class UniqueName : public BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ - BaseClass, Method)<__VA_ARGS__> { \ - public: \ - UniqueName() { this->SetName(#BaseClass "<" #__VA_ARGS__ ">/" #Method); } \ - }; \ - BENCHMARK_PRIVATE_DECLARE(BaseClass##_##Method##_Benchmark) = \ - (::benchmark::internal::RegisterBenchmarkInternal( \ - ::benchmark::internal::make_unique())) - -#define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \ - BENCHMARK_DISABLE_COUNTER_WARNING \ - BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \ - BaseClass, Method, BENCHMARK_PRIVATE_NAME(BaseClass##Method), \ - __VA_ARGS__) \ - BENCHMARK_RESTORE_COUNTER_WARNING - -// This macro will define and register a benchmark within a fixture class. -#define BENCHMARK_F(BaseClass, Method) \ - BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ - BENCHMARK_REGISTER_F(BaseClass, Method); \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_TEMPLATE1_F(BaseClass, Method, a) \ - BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ - BENCHMARK_REGISTER_F(BaseClass, Method); \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_TEMPLATE2_F(BaseClass, Method, a, b) \ - BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ - BENCHMARK_REGISTER_F(BaseClass, Method); \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -#define BENCHMARK_TEMPLATE_F(BaseClass, Method, ...) \ - BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ - BENCHMARK_REGISTER_F(BaseClass, Method); \ - void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase - -// Helper macro to create a main routine in a test that runs the benchmarks -// Note the workaround for Hexagon simulator passing argc != 0, argv = NULL. -#define BENCHMARK_MAIN() \ - int main(int argc, char** argv) { \ - benchmark::MaybeReenterWithoutASLR(argc, argv); \ - char arg0_default[] = "benchmark"; \ - char* args_default = reinterpret_cast(arg0_default); \ - if (!argv) { \ - argc = 1; \ - argv = &args_default; \ - } \ - ::benchmark::Initialize(&argc, argv); \ - if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; \ - ::benchmark::RunSpecifiedBenchmarks(); \ - ::benchmark::Shutdown(); \ - return 0; \ - } \ - int main(int, char**) - -// ------------------------------------------------------ -// Benchmark Reporters - -namespace benchmark { - -struct BENCHMARK_EXPORT CPUInfo { - struct CacheInfo { - std::string type; - int level; - int size; - int num_sharing; - }; - - enum Scaling { UNKNOWN, ENABLED, DISABLED }; - - int num_cpus; - Scaling scaling; - double cycles_per_second; - std::vector caches; - std::vector load_avg; - - static const CPUInfo& Get(); - - private: - CPUInfo(); - BENCHMARK_DISALLOW_COPY_AND_ASSIGN(CPUInfo); -}; - -// Adding Struct for System Information -struct BENCHMARK_EXPORT SystemInfo { - enum class ASLR { UNKNOWN, ENABLED, DISABLED }; - - std::string name; - ASLR ASLRStatus; - static const SystemInfo& Get(); - - private: - SystemInfo(); - BENCHMARK_DISALLOW_COPY_AND_ASSIGN(SystemInfo); -}; - -// BenchmarkName contains the components of the Benchmark's name -// which allows individual fields to be modified or cleared before -// building the final name using 'str()'. -struct BENCHMARK_EXPORT BenchmarkName { - std::string function_name; - std::string args; - std::string min_time; - std::string min_warmup_time; - std::string iterations; - std::string repetitions; - std::string time_type; - std::string threads; - - // Return the full name of the benchmark with each non-empty - // field separated by a '/' - std::string str() const; -}; - -// Interface for custom benchmark result printers. -// By default, benchmark reports are printed to stdout. However an application -// can control the destination of the reports by calling -// RunSpecifiedBenchmarks and passing it a custom reporter object. -// The reporter object must implement the following interface. -class BENCHMARK_EXPORT BenchmarkReporter { - public: - struct Context { - CPUInfo const& cpu_info; - SystemInfo const& sys_info; - // The number of chars in the longest benchmark name. - size_t name_field_width = 0; - static const char* executable_name; - Context(); - }; - - struct BENCHMARK_EXPORT Run { - static const int64_t no_repetition_index = -1; - enum RunType { RT_Iteration, RT_Aggregate }; - - Run() - : run_type(RT_Iteration), - aggregate_unit(kTime), - skipped(internal::NotSkipped), - iterations(1), - threads(1), - time_unit(GetDefaultTimeUnit()), - real_accumulated_time(0), - cpu_accumulated_time(0), - max_heapbytes_used(0), - use_real_time_for_initial_big_o(false), - complexity(oNone), - complexity_lambda(), - complexity_n(0), - statistics(), - report_big_o(false), - report_rms(false), - allocs_per_iter(0.0) {} - - std::string benchmark_name() const; - BenchmarkName run_name; - int64_t family_index; - int64_t per_family_instance_index; - RunType run_type; - std::string aggregate_name; - StatisticUnit aggregate_unit; - std::string report_label; // Empty if not set by benchmark. - internal::Skipped skipped; - std::string skip_message; - - IterationCount iterations; - int64_t threads; - int64_t repetition_index; - int64_t repetitions; - TimeUnit time_unit; - double real_accumulated_time; - double cpu_accumulated_time; - - // Return a value representing the real time per iteration in the unit - // specified by 'time_unit'. - // NOTE: If 'iterations' is zero the returned value represents the - // accumulated time. - double GetAdjustedRealTime() const; - - // Return a value representing the cpu time per iteration in the unit - // specified by 'time_unit'. - // NOTE: If 'iterations' is zero the returned value represents the - // accumulated time. - double GetAdjustedCPUTime() const; - - // This is set to 0.0 if memory tracing is not enabled. - double max_heapbytes_used; - - // By default Big-O is computed for CPU time, but that is not what you want - // to happen when manual time was requested, which is stored as real time. - bool use_real_time_for_initial_big_o; - - // Keep track of arguments to compute asymptotic complexity - BigO complexity; - BigOFunc* complexity_lambda; - ComplexityN complexity_n; - - // what statistics to compute from the measurements - const std::vector* statistics; - - // Inform print function whether the current run is a complexity report - bool report_big_o; - bool report_rms; - - UserCounters counters; - - // Memory metrics. - MemoryManager::Result memory_result; - double allocs_per_iter; - }; - - struct PerFamilyRunReports { - PerFamilyRunReports() : num_runs_total(0), num_runs_done(0) {} - - // How many runs will all instances of this benchmark perform? - int num_runs_total; - - // How many runs have happened already? - int num_runs_done; - - // The reports about (non-errneous!) runs of this family. - std::vector Runs; - }; - - // Construct a BenchmarkReporter with the output stream set to 'std::cout' - // and the error stream set to 'std::cerr' - BenchmarkReporter(); - - // Called once for every suite of benchmarks run. - // The parameter "context" contains information that the - // reporter may wish to use when generating its report, for example the - // platform under which the benchmarks are running. The benchmark run is - // never started if this function returns false, allowing the reporter - // to skip runs based on the context information. - virtual bool ReportContext(const Context& context) = 0; - - // Called once for each group of benchmark runs, gives information about - // the configurations of the runs. - virtual void ReportRunsConfig(double /*min_time*/, - bool /*has_explicit_iters*/, - IterationCount /*iters*/) {} - - // Called once for each group of benchmark runs, gives information about - // cpu-time and heap memory usage during the benchmark run. If the group - // of runs contained more than two entries then 'report' contains additional - // elements representing the mean and standard deviation of those runs. - // Additionally if this group of runs was the last in a family of benchmarks - // 'reports' contains additional entries representing the asymptotic - // complexity and RMS of that benchmark family. - virtual void ReportRuns(const std::vector& report) = 0; - - // Called once and only once after ever group of benchmarks is run and - // reported. - virtual void Finalize() {} - - // REQUIRES: The object referenced by 'out' is valid for the lifetime - // of the reporter. - void SetOutputStream(std::ostream* out) { - assert(out); - output_stream_ = out; - } - - // REQUIRES: The object referenced by 'err' is valid for the lifetime - // of the reporter. - void SetErrorStream(std::ostream* err) { - assert(err); - error_stream_ = err; - } - - std::ostream& GetOutputStream() const { return *output_stream_; } - - std::ostream& GetErrorStream() const { return *error_stream_; } - - virtual ~BenchmarkReporter(); - - // Write a human readable string to 'out' representing the specified - // 'context'. - // REQUIRES: 'out' is non-null. - static void PrintBasicContext(std::ostream* out, Context const& context); - - private: - std::ostream* output_stream_; - std::ostream* error_stream_; -}; - -// Simple reporter that outputs benchmark data to the console. This is the -// default reporter used by RunSpecifiedBenchmarks(). -class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter { - public: - enum OutputOptions { - OO_None = 0, - OO_Color = 1, - OO_Tabular = 2, - OO_ColorTabular = OO_Color | OO_Tabular, - OO_Defaults = OO_ColorTabular - }; - explicit ConsoleReporter(OutputOptions opts_ = OO_Defaults) - : output_options_(opts_), name_field_width_(0), printed_header_(false) {} - - bool ReportContext(const Context& context) override; - void ReportRuns(const std::vector& reports) override; - - protected: - virtual void PrintRunData(const Run& result); - virtual void PrintHeader(const Run& run); - - OutputOptions output_options_; - size_t name_field_width_; - UserCounters prev_counters_; - bool printed_header_; -}; - -class BENCHMARK_EXPORT JSONReporter : public BenchmarkReporter { - public: - JSONReporter() : first_report_(true) {} - bool ReportContext(const Context& context) override; - void ReportRuns(const std::vector& reports) override; - void Finalize() override; - - private: - void PrintRunData(const Run& run); - - bool first_report_; -}; - -class BENCHMARK_EXPORT BENCHMARK_DEPRECATED_MSG( - "The CSV Reporter will be removed in a future release") CSVReporter - : public BenchmarkReporter { - public: - CSVReporter() : printed_header_(false) {} - bool ReportContext(const Context& context) override; - void ReportRuns(const std::vector& reports) override; - - private: - void PrintRunData(const Run& run); - - bool printed_header_; - std::set user_counter_names_; -}; - -inline const char* GetTimeUnitString(TimeUnit unit) { - switch (unit) { - case kSecond: - return "s"; - case kMillisecond: - return "ms"; - case kMicrosecond: - return "us"; - case kNanosecond: - return "ns"; - } - BENCHMARK_UNREACHABLE(); -} - -inline double GetTimeUnitMultiplier(TimeUnit unit) { - switch (unit) { - case kSecond: - return 1; - case kMillisecond: - return 1e3; - case kMicrosecond: - return 1e6; - case kNanosecond: - return 1e9; - } - BENCHMARK_UNREACHABLE(); -} - -// Creates a list of integer values for the given range and multiplier. -// This can be used together with ArgsProduct() to allow multiple ranges -// with different multipliers. -// Example: -// ArgsProduct({ -// CreateRange(0, 1024, /*multi=*/32), -// CreateRange(0, 100, /*multi=*/4), -// CreateDenseRange(0, 4, /*step=*/1), -// }); -BENCHMARK_EXPORT -std::vector CreateRange(int64_t lo, int64_t hi, int multi); - -// Creates a list of integer values for the given range and step. -BENCHMARK_EXPORT -std::vector CreateDenseRange(int64_t start, int64_t limit, int step); - -} // namespace benchmark - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif +#include "benchmark/benchmark_api.h" +#include "benchmark/counter.h" +#include "benchmark/macros.h" +#include "benchmark/managers.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" +#include "benchmark/statistics.h" +#include "benchmark/sysinfo.h" +#include "benchmark/types.h" +#include "benchmark/utils.h" #endif // BENCHMARK_BENCHMARK_H_ diff --git a/include/benchmark/benchmark_api.h b/include/benchmark/benchmark_api.h new file mode 100644 index 0000000000..6d98aba581 --- /dev/null +++ b/include/benchmark/benchmark_api.h @@ -0,0 +1,292 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_BENCHMARK_API_H_ +#define BENCHMARK_BENCHMARK_API_H_ + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + +#include +#include +#include +#include +#include + +#include "benchmark/counter.h" +#include "benchmark/macros.h" +#include "benchmark/state.h" +#include "benchmark/statistics.h" +#include "benchmark/types.h" + +namespace benchmark { + +const char kDefaultMinTimeStr[] = "0.5s"; + +BENCHMARK_EXPORT void MaybeReenterWithoutASLR(int, char**); + +BENCHMARK_EXPORT std::string GetBenchmarkVersion(); + +BENCHMARK_EXPORT void PrintDefaultHelp(); + +BENCHMARK_EXPORT void Initialize(int* argc, char** argv, + void (*HelperPrintf)() = PrintDefaultHelp); +BENCHMARK_EXPORT void Shutdown(); + +BENCHMARK_EXPORT bool ReportUnrecognizedArguments(int argc, char** argv); + +BENCHMARK_EXPORT std::string GetBenchmarkFilter(); + +BENCHMARK_EXPORT void SetBenchmarkFilter(std::string value); + +BENCHMARK_EXPORT int32_t GetBenchmarkVerbosity(); + +BENCHMARK_EXPORT BenchmarkReporter* CreateDefaultDisplayReporter(); + +BENCHMARK_EXPORT size_t RunSpecifiedBenchmarks(); +BENCHMARK_EXPORT size_t RunSpecifiedBenchmarks(std::string spec); + +BENCHMARK_EXPORT size_t +RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter); +BENCHMARK_EXPORT size_t +RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, std::string spec); + +BENCHMARK_EXPORT size_t RunSpecifiedBenchmarks( + BenchmarkReporter* display_reporter, BenchmarkReporter* file_reporter); +BENCHMARK_EXPORT size_t +RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, + BenchmarkReporter* file_reporter, std::string spec); + +BENCHMARK_EXPORT TimeUnit GetDefaultTimeUnit(); + +BENCHMARK_EXPORT void SetDefaultTimeUnit(TimeUnit unit); + +BENCHMARK_EXPORT +void AddCustomContext(std::string key, std::string value); + +struct ThreadRunnerBase { + virtual ~ThreadRunnerBase() {} + virtual void RunThreads(const std::function& fn) = 0; +}; + +using threadrunner_factory = + std::function(int)>; + +namespace internal { +class BenchmarkFamilies; +class BenchmarkInstance; +} // namespace internal + +class BENCHMARK_EXPORT Benchmark { + public: + virtual ~Benchmark(); + + Benchmark* Name(const std::string& name); + Benchmark* Arg(int64_t x); + Benchmark* Unit(TimeUnit unit); + Benchmark* Range(int64_t start, int64_t limit); + Benchmark* DenseRange(int64_t start, int64_t limit, int step = 1); + Benchmark* Args(const std::vector& args); + Benchmark* ArgPair(int64_t x, int64_t y) { + std::vector args; + args.push_back(x); + args.push_back(y); + return Args(args); + } + Benchmark* Ranges(const std::vector>& ranges); + Benchmark* ArgsProduct(const std::vector>& arglists); + Benchmark* ArgName(const std::string& name); + Benchmark* ArgNames(const std::vector& names); + Benchmark* RangePair(int64_t lo1, int64_t hi1, int64_t lo2, int64_t hi2) { + std::vector> ranges; + ranges.push_back(std::make_pair(lo1, hi1)); + ranges.push_back(std::make_pair(lo2, hi2)); + return Ranges(ranges); + } + Benchmark* Setup(callback_function&&); + Benchmark* Setup(const callback_function&); + Benchmark* Teardown(callback_function&&); + Benchmark* Teardown(const callback_function&); + Benchmark* Apply(const std::function&); + Benchmark* RangeMultiplier(int multiplier); + Benchmark* MinTime(double t); + Benchmark* MinWarmUpTime(double t); + Benchmark* Iterations(IterationCount n); + Benchmark* Repetitions(int n); + Benchmark* ReportAggregatesOnly(bool value = true); + Benchmark* DisplayAggregatesOnly(bool value = true); + Benchmark* MeasureProcessCPUTime(); + Benchmark* UseRealTime(); + Benchmark* UseManualTime(); + Benchmark* Complexity(BigO complexity = benchmark::oAuto); + Benchmark* Complexity(BigOFunc* complexity); + Benchmark* ComputeStatistics(const std::string& name, + StatisticsFunc* statistics, + StatisticUnit unit = kTime); + Benchmark* Threads(int t); + Benchmark* ThreadRange(int min_threads, int max_threads); + Benchmark* DenseThreadRange(int min_threads, int max_threads, int stride = 1); + Benchmark* ThreadPerCpu(); + Benchmark* ThreadRunner(threadrunner_factory&& factory); + + virtual void Run(State& state) = 0; + + TimeUnit GetTimeUnit() const; + + protected: + explicit Benchmark(const std::string& name); + void SetName(const std::string& name); + + public: + const char* GetName() const; + int ArgsCnt() const; + const char* GetArgName(int arg) const; + + private: + friend class internal::BenchmarkFamilies; + friend class internal::BenchmarkInstance; + + std::string name_; + internal::AggregationReportMode aggregation_report_mode_; + std::vector arg_names_; + std::vector> args_; + + TimeUnit time_unit_; + bool use_default_time_unit_; + + int range_multiplier_; + double min_time_; + double min_warmup_time_; + IterationCount iterations_; + int repetitions_; + bool measure_process_cpu_time_; + bool use_real_time_; + bool use_manual_time_; + BigO complexity_; + BigOFunc* complexity_lambda_; + std::vector statistics_; + std::vector thread_counts_; + + callback_function setup_; + callback_function teardown_; + + threadrunner_factory threadrunner_; + + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(Benchmark); +}; + +namespace internal { +typedef BENCHMARK_DEPRECATED_MSG( + "Use ::benchmark::Benchmark instead")::benchmark::Benchmark Benchmark; +typedef BENCHMARK_DEPRECATED_MSG( + "Use ::benchmark::threadrunner_factory instead")::benchmark:: + threadrunner_factory threadrunner_factory; + +typedef void(Function)(State&); + +BENCHMARK_EXPORT ::benchmark::Benchmark* RegisterBenchmarkInternal( + std::unique_ptr<::benchmark::Benchmark>); +BENCHMARK_EXPORT std::map*& GetGlobalContext(); +BENCHMARK_EXPORT void UseCharPointer(char const volatile*); +BENCHMARK_EXPORT int InitializeStreams(); +BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); +} // namespace internal + +Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn); + +template +Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn); + +BENCHMARK_EXPORT void ClearRegisteredBenchmarks(); + +namespace internal { +class BENCHMARK_EXPORT FunctionBenchmark : public benchmark::Benchmark { + public: + FunctionBenchmark(const std::string& name, Function* func) + : Benchmark(name), func_(func) {} + void Run(State& st) override; + + private: + Function* func_; +}; + +template +class LambdaBenchmark : public benchmark::Benchmark { + public: + void Run(State& st) override { lambda_(st); } + template + LambdaBenchmark(const std::string& name, OLambda&& lam) + : Benchmark(name), lambda_(std::forward(lam)) {} + + private: + LambdaBenchmark(LambdaBenchmark const&) = delete; + Lambda lambda_; +}; +} // namespace internal + +inline Benchmark* RegisterBenchmark(const std::string& name, + internal::Function* fn) { + return internal::RegisterBenchmarkInternal( + ::benchmark::internal::make_unique(name, + fn)); +} + +template +Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) { + using BenchType = + internal::LambdaBenchmark::type>; + return internal::RegisterBenchmarkInternal( + ::benchmark::internal::make_unique(name, + std::forward(fn))); +} + +template +Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn, + Args&&... args) { + return benchmark::RegisterBenchmark( + name, [=](benchmark::State& st) { fn(st, args...); }); +} + +class Fixture : public Benchmark { + public: + Fixture() : Benchmark("") {} + void Run(State& st) override { + this->SetUp(st); + this->BenchmarkCase(st); + this->TearDown(st); + } + virtual void SetUp(const State&) {} + virtual void TearDown(const State&) {} + virtual void SetUp(State& st) { SetUp(const_cast(st)); } + virtual void TearDown(State& st) { TearDown(const_cast(st)); } + + protected: + virtual void BenchmarkCase(State&) = 0; +}; + +BENCHMARK_EXPORT +std::vector CreateRange(int64_t lo, int64_t hi, int multi); + +BENCHMARK_EXPORT +std::vector CreateDenseRange(int64_t start, int64_t limit, int step); + +} // namespace benchmark + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // BENCHMARK_BENCHMARK_API_H_ diff --git a/include/benchmark/counter.h b/include/benchmark/counter.h new file mode 100644 index 0000000000..8db5d8dad7 --- /dev/null +++ b/include/benchmark/counter.h @@ -0,0 +1,80 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_COUNTER_H_ +#define BENCHMARK_COUNTER_H_ + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + +#include +#include + +#include "benchmark/macros.h" +#include "benchmark/types.h" + +namespace benchmark { + +class BENCHMARK_EXPORT Counter { + public: + enum Flags { + kDefaults = 0, + kIsRate = 1 << 0, + kAvgThreads = 1 << 1, + kAvgThreadsRate = kIsRate | kAvgThreads, + kIsIterationInvariant = 1 << 2, + kIsIterationInvariantRate = kIsRate | kIsIterationInvariant, + kAvgIterations = 1 << 3, + kAvgIterationsRate = kIsRate | kAvgIterations, + kInvert = 1 << 31 + }; + + enum OneK { kIs1000 = 1000, kIs1024 = 1024 }; + + double value; + Flags flags; + OneK oneK; + + BENCHMARK_ALWAYS_INLINE + Counter(double v = 0., Flags f = kDefaults, OneK k = kIs1000) + : value(v), flags(f), oneK(k) {} + + BENCHMARK_ALWAYS_INLINE operator double const&() const { return value; } + BENCHMARK_ALWAYS_INLINE operator double&() { return value; } +}; + +Counter::Flags inline operator|(const Counter::Flags& LHS, + const Counter::Flags& RHS) { + return static_cast(static_cast(LHS) | + static_cast(RHS)); +} + +using UserCounters = std::map; + +namespace internal { +void Finish(UserCounters* l, IterationCount iterations, double cpu_time, + double num_threads); +void Increment(UserCounters* l, UserCounters const& r); +bool SameNames(UserCounters const& l, UserCounters const& r); +} // namespace internal + +} // namespace benchmark + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // BENCHMARK_COUNTER_H_ diff --git a/include/benchmark/macros.h b/include/benchmark/macros.h new file mode 100644 index 0000000000..17f19ac272 --- /dev/null +++ b/include/benchmark/macros.h @@ -0,0 +1,136 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_MACROS_H_ +#define BENCHMARK_MACROS_H_ + +#if defined(_MSC_VER) +#include +#endif + +#include + +#define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + TypeName& operator=(const TypeName&) = delete + +#ifdef BENCHMARK_HAS_CXX17 +#define BENCHMARK_UNUSED [[maybe_unused]] +#elif defined(__GNUC__) || defined(__clang__) +#define BENCHMARK_UNUSED __attribute__((unused)) +#else +#define BENCHMARK_UNUSED +#endif + +#if defined(__clang__) +#define BENCHMARK_DONT_OPTIMIZE __attribute__((optnone)) +#elif defined(__GNUC__) || defined(__GNUG__) +#define BENCHMARK_DONT_OPTIMIZE __attribute__((optimize(0))) +#else +#define BENCHMARK_DONT_OPTIMIZE +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define BENCHMARK_ALWAYS_INLINE __attribute__((always_inline)) +#elif defined(_MSC_VER) && !defined(__clang__) +#define BENCHMARK_ALWAYS_INLINE __forceinline +#define __func__ __FUNCTION__ +#else +#define BENCHMARK_ALWAYS_INLINE +#endif + +#define BENCHMARK_INTERNAL_TOSTRING2(x) #x +#define BENCHMARK_INTERNAL_TOSTRING(x) BENCHMARK_INTERNAL_TOSTRING2(x) + +#if (defined(__GNUC__) && !defined(__NVCC__) && !defined(__NVCOMPILER)) || \ + defined(__clang__) +#define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) +#define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("GCC diagnostic pop") +#elif defined(__NVCOMPILER) +#define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) +#define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ + _Pragma("diagnostic push") \ + _Pragma("diag_suppress deprecated_entity_with_custom_message") +#define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("diagnostic pop") +#elif defined(_MSC_VER) +#define BENCHMARK_BUILTIN_EXPECT(x, y) x +#define BENCHMARK_DEPRECATED_MSG(msg) __declspec(deprecated(msg)) +#define BENCHMARK_WARNING_MSG(msg) \ + __pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING( \ + __LINE__) ") : warning note: " msg)) +#define BENCHMARK_DISABLE_DEPRECATED_WARNING \ + __pragma(warning(push)) __pragma(warning(disable : 4996)) +#define BENCHMARK_RESTORE_DEPRECATED_WARNING __pragma(warning(pop)) +#else +#define BENCHMARK_BUILTIN_EXPECT(x, y) x +#define BENCHMARK_DEPRECATED_MSG(msg) +#define BENCHMARK_WARNING_MSG(msg) \ + __pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING( \ + __LINE__) ") : warning note: " msg)) +#define BENCHMARK_DISABLE_DEPRECATED_WARNING +#define BENCHMARK_RESTORE_DEPRECATED_WARNING +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#define BENCHMARK_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if defined(__GNUC__) || __has_builtin(__builtin_unreachable) +#define BENCHMARK_UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +#define BENCHMARK_UNREACHABLE() __assume(false) +#else +#define BENCHMARK_UNREACHABLE() ((void)0) +#endif + +#if defined(__GNUC__) +#if defined(__i386__) || defined(__x86_64__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#elif defined(__powerpc64__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 128 +#elif defined(__aarch64__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#elif defined(__arm__) +#if defined(__ARM_ARCH_5T__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 32 +#elif defined(__ARM_ARCH_7A__) +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#endif +#endif +#endif + +#ifndef BENCHMARK_INTERNAL_CACHELINE_SIZE +#define BENCHMARK_INTERNAL_CACHELINE_SIZE 64 +#endif + +#if defined(__GNUC__) +#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED \ + __attribute__((aligned(BENCHMARK_INTERNAL_CACHELINE_SIZE))) +#elif defined(_MSC_VER) +#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED \ + __declspec(align(BENCHMARK_INTERNAL_CACHELINE_SIZE)) +#else +#define BENCHMARK_INTERNAL_CACHELINE_ALIGNED +#endif + +#endif // BENCHMARK_MACROS_H_ diff --git a/include/benchmark/managers.h b/include/benchmark/managers.h new file mode 100644 index 0000000000..e8b6cd4749 --- /dev/null +++ b/include/benchmark/managers.h @@ -0,0 +1,66 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_MANAGERS_H_ +#define BENCHMARK_MANAGERS_H_ + +#include + +#include + +#include "benchmark/macros.h" +#include "benchmark/types.h" + +namespace benchmark { + +class MemoryManager { + public: + static constexpr int64_t TombstoneValue = std::numeric_limits::max(); + + struct Result { + Result() + : num_allocs(0), + max_bytes_used(0), + total_allocated_bytes(TombstoneValue), + net_heap_growth(TombstoneValue), + memory_iterations(0) {} + + int64_t num_allocs; + int64_t max_bytes_used; + int64_t total_allocated_bytes; + int64_t net_heap_growth; + IterationCount memory_iterations; + }; + + virtual ~MemoryManager() {} + virtual void Start() = 0; + virtual void Stop(Result& result) = 0; +}; + +BENCHMARK_EXPORT +void RegisterMemoryManager(MemoryManager* memory_manager); + +class ProfilerManager { + public: + virtual ~ProfilerManager() {} + virtual void AfterSetupStart() = 0; + virtual void BeforeTeardownStop() = 0; +}; + +BENCHMARK_EXPORT +void RegisterProfilerManager(ProfilerManager* profiler_manager); + +} // namespace benchmark + +#endif // BENCHMARK_MANAGERS_H_ diff --git a/include/benchmark/registration.h b/include/benchmark/registration.h new file mode 100644 index 0000000000..5ac08de3fc --- /dev/null +++ b/include/benchmark/registration.h @@ -0,0 +1,258 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_REGISTRATION_H_ +#define BENCHMARK_REGISTRATION_H_ + +#include "benchmark/benchmark_api.h" +#include "benchmark/macros.h" + +#if defined(__clang__) +#define BENCHMARK_DISABLE_COUNTER_WARNING \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunknown-warning-option\"") \ + _Pragma("GCC diagnostic ignored \"-Wc2y-extensions\"") +#define BENCHMARK_RESTORE_COUNTER_WARNING _Pragma("GCC diagnostic pop") +#else +#define BENCHMARK_DISABLE_COUNTER_WARNING +#define BENCHMARK_RESTORE_COUNTER_WARNING +#endif + +BENCHMARK_DISABLE_COUNTER_WARNING +#if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) +#define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__ +#else +#define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__ +#endif +BENCHMARK_RESTORE_COUNTER_WARNING + +#define BENCHMARK_PRIVATE_NAME(...) \ + BENCHMARK_PRIVATE_CONCAT(benchmark_uniq_, BENCHMARK_PRIVATE_UNIQUE_ID, \ + __VA_ARGS__) + +#define BENCHMARK_PRIVATE_CONCAT(a, b, c) BENCHMARK_PRIVATE_CONCAT2(a, b, c) +#define BENCHMARK_PRIVATE_CONCAT2(a, b, c) a##b##c +#define BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method) \ + BaseClass##_##Method##_Benchmark + +#define BENCHMARK_PRIVATE_DECLARE(n) \ + BENCHMARK_DISABLE_COUNTER_WARNING \ + static ::benchmark::Benchmark const* const BENCHMARK_PRIVATE_NAME(n) \ + BENCHMARK_RESTORE_COUNTER_WARNING BENCHMARK_UNUSED + +#define BENCHMARK(...) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #__VA_ARGS__, \ + static_cast<::benchmark::internal::Function*>(__VA_ARGS__)))) + +#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) +#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->Args({(a1), (a2)}) +#define BENCHMARK_WITH_UNIT(n, t) BENCHMARK(n)->Unit((t)) +#define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi)) +#define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ + BENCHMARK(n)->RangePair({{(l1), (h1)}, {(l2), (h2)}}) + +#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #func "/" #test_case_name, \ + [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) + +#define BENCHMARK_NAMED(func, test_case_name) \ + BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #func "/" #test_case_name, \ + static_cast<::benchmark::internal::Function*>(func)))) + +#define BENCHMARK_TEMPLATE1(n, a) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #n "<" #a ">", \ + static_cast<::benchmark::internal::Function*>(n)))) + +#define BENCHMARK_TEMPLATE2(n, a, b) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #n "<" #a "," #b ">", \ + static_cast<::benchmark::internal::Function*>(n)))) + +#define BENCHMARK_TEMPLATE(n, ...) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #n "<" #__VA_ARGS__ ">", \ + static_cast<::benchmark::internal::Function*>(n<__VA_ARGS__>)))) + +#define BENCHMARK_TEMPLATE1_CAPTURE(func, a, test_case_name, ...) \ + BENCHMARK_CAPTURE(func, test_case_name, __VA_ARGS__) + +#define BENCHMARK_TEMPLATE2_CAPTURE(func, a, b, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(func) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique< \ + ::benchmark::internal::FunctionBenchmark>( \ + #func "<" #a "," #b ">" \ + "/" #test_case_name, \ + [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) + +#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) override; \ + }; + +#define BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "<" #a ">/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) override; \ + }; + +#define BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "<" #a "," #b ">/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) override; \ + }; + +#define BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, ...) \ + class BaseClass##_##Method##_Benchmark : public BaseClass<__VA_ARGS__> { \ + public: \ + BaseClass##_##Method##_Benchmark() { \ + this->SetName(#BaseClass "<" #__VA_ARGS__ ">/" #Method); \ + } \ + \ + protected: \ + void BenchmarkCase(::benchmark::State&) override; \ + }; + +#define BENCHMARK_DEFINE_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE1_DEFINE_F(BaseClass, Method, a) \ + BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE2_DEFINE_F(BaseClass, Method, a, b) \ + BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_REGISTER_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_REGISTER_F(BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)) + +#define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ + BENCHMARK_PRIVATE_DECLARE(TestName) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique())) + +#define BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ + BaseClass##_##Method##_BenchmarkTemplate + +#define BENCHMARK_TEMPLATE_METHOD_F(BaseClass, Method) \ + template \ + class BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F(BaseClass, Method) \ + : public BaseClass { \ + protected: \ + using Base = BaseClass; \ + void BenchmarkCase(::benchmark::State&) override; \ + }; \ + template \ + void BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ + BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F(BaseClass, Method, \ + UniqueName, ...) \ + class UniqueName : public BENCHMARK_TEMPLATE_PRIVATE_CONCAT_NAME_F( \ + BaseClass, Method)<__VA_ARGS__> { \ + public: \ + UniqueName() { this->SetName(#BaseClass "<" #__VA_ARGS__ ">/" #Method); } \ + }; \ + BENCHMARK_PRIVATE_DECLARE(BaseClass##_##Method##_Benchmark) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + ::benchmark::internal::make_unique())) + +#define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \ + BENCHMARK_DISABLE_COUNTER_WARNING \ + BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \ + BaseClass, Method, BENCHMARK_PRIVATE_NAME(BaseClass##Method), \ + __VA_ARGS__) \ + BENCHMARK_RESTORE_COUNTER_WARNING + +#define BENCHMARK_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE1_F(BaseClass, Method, a) \ + BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE2_F(BaseClass, Method, a, b) \ + BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_TEMPLATE_F(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ + void BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::BenchmarkCase + +#define BENCHMARK_MAIN() \ + int main(int argc, char** argv) { \ + benchmark::MaybeReenterWithoutASLR(argc, argv); \ + char arg0_default[] = "benchmark"; \ + char* args_default = reinterpret_cast(arg0_default); \ + if (!argv) { \ + argc = 1; \ + argv = &args_default; \ + } \ + ::benchmark::Initialize(&argc, argv); \ + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; \ + ::benchmark::RunSpecifiedBenchmarks(); \ + ::benchmark::Shutdown(); \ + return 0; \ + } \ + int main(int, char**) + +#endif // BENCHMARK_REGISTRATION_H_ diff --git a/include/benchmark/reporter.h b/include/benchmark/reporter.h new file mode 100644 index 0000000000..be242bec3a --- /dev/null +++ b/include/benchmark/reporter.h @@ -0,0 +1,238 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_REPORTER_H_ +#define BENCHMARK_REPORTER_H_ + +#if defined(_MSC_VER) +#pragma warning(push) +// C4251: needs to have dll-interface to be used by clients of class +#pragma warning(disable : 4251) +#endif + +#include +#include +#include +#include +#include + +#include "benchmark/counter.h" +#include "benchmark/macros.h" +#include "benchmark/managers.h" +#include "benchmark/statistics.h" +#include "benchmark/sysinfo.h" +#include "benchmark/types.h" + +namespace benchmark { + +struct BENCHMARK_EXPORT BenchmarkName { + std::string function_name; + std::string args; + std::string min_time; + std::string min_warmup_time; + std::string iterations; + std::string repetitions; + std::string time_type; + std::string threads; + + std::string str() const; +}; + +class BENCHMARK_EXPORT BenchmarkReporter { + public: + struct Context { + CPUInfo const& cpu_info; + SystemInfo const& sys_info; + size_t name_field_width = 0; + static const char* executable_name; + Context(); + }; + + struct BENCHMARK_EXPORT Run { + static const int64_t no_repetition_index = -1; + enum RunType { RT_Iteration, RT_Aggregate }; + + Run() + : run_type(RT_Iteration), + aggregate_unit(kTime), + skipped(internal::NotSkipped), + iterations(1), + threads(1), + time_unit(kNanosecond), + real_accumulated_time(0), + cpu_accumulated_time(0), + max_heapbytes_used(0), + use_real_time_for_initial_big_o(false), + complexity(oNone), + complexity_lambda(), + complexity_n(0), + statistics(), + report_big_o(false), + report_rms(false), + allocs_per_iter(0.0) {} + + std::string benchmark_name() const; + BenchmarkName run_name; + int64_t family_index; + int64_t per_family_instance_index; + RunType run_type; + std::string aggregate_name; + StatisticUnit aggregate_unit; + std::string report_label; + internal::Skipped skipped; + std::string skip_message; + + IterationCount iterations; + int64_t threads; + int64_t repetition_index; + int64_t repetitions; + TimeUnit time_unit; + double real_accumulated_time; + double cpu_accumulated_time; + + double GetAdjustedRealTime() const; + double GetAdjustedCPUTime() const; + + double max_heapbytes_used; + bool use_real_time_for_initial_big_o; + BigO complexity; + BigOFunc* complexity_lambda; + ComplexityN complexity_n; + const std::vector* statistics; + bool report_big_o; + bool report_rms; + UserCounters counters; + MemoryManager::Result memory_result; + double allocs_per_iter; + }; + + struct PerFamilyRunReports { + PerFamilyRunReports() : num_runs_total(0), num_runs_done(0) {} + int num_runs_total; + int num_runs_done; + std::vector Runs; + }; + + BenchmarkReporter(); + virtual bool ReportContext(const Context& context) = 0; + virtual void ReportRunsConfig(double /*min_time*/, + bool /*has_explicit_iters*/, + IterationCount /*iters*/) {} + virtual void ReportRuns(const std::vector& report) = 0; + virtual void Finalize() {} + + void SetOutputStream(std::ostream* out) { + assert(out); + output_stream_ = out; + } + void SetErrorStream(std::ostream* err) { + assert(err); + error_stream_ = err; + } + std::ostream& GetOutputStream() const { return *output_stream_; } + std::ostream& GetErrorStream() const { return *error_stream_; } + virtual ~BenchmarkReporter(); + static void PrintBasicContext(std::ostream* out, Context const& context); + + private: + std::ostream* output_stream_; + std::ostream* error_stream_; +}; + +class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter { + public: + enum OutputOptions { + OO_None = 0, + OO_Color = 1, + OO_Tabular = 2, + OO_ColorTabular = OO_Color | OO_Tabular, + OO_Defaults = OO_ColorTabular + }; + explicit ConsoleReporter(OutputOptions opts_ = OO_Defaults) + : output_options_(opts_), name_field_width_(0), printed_header_(false) {} + + bool ReportContext(const Context& context) override; + void ReportRuns(const std::vector& reports) override; + + protected: + virtual void PrintRunData(const Run& result); + virtual void PrintHeader(const Run& run); + + OutputOptions output_options_; + size_t name_field_width_; + UserCounters prev_counters_; + bool printed_header_; +}; + +class BENCHMARK_EXPORT JSONReporter : public BenchmarkReporter { + public: + JSONReporter() : first_report_(true) {} + bool ReportContext(const Context& context) override; + void ReportRuns(const std::vector& reports) override; + void Finalize() override; + + private: + void PrintRunData(const Run& run); + bool first_report_; +}; + +class BENCHMARK_EXPORT BENCHMARK_DEPRECATED_MSG( + "The CSV Reporter will be removed in a future release") CSVReporter + : public BenchmarkReporter { + public: + CSVReporter() : printed_header_(false) {} + bool ReportContext(const Context& context) override; + void ReportRuns(const std::vector& reports) override; + + private: + void PrintRunData(const Run& run); + bool printed_header_; + std::set user_counter_names_; +}; + +inline const char* GetTimeUnitString(TimeUnit unit) { + switch (unit) { + case kSecond: + return "s"; + case kMillisecond: + return "ms"; + case kMicrosecond: + return "us"; + case kNanosecond: + return "ns"; + } + BENCHMARK_UNREACHABLE(); +} + +inline double GetTimeUnitMultiplier(TimeUnit unit) { + switch (unit) { + case kSecond: + return 1; + case kMillisecond: + return 1e3; + case kMicrosecond: + return 1e6; + case kNanosecond: + return 1e9; + } + BENCHMARK_UNREACHABLE(); +} + +} // namespace benchmark + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // BENCHMARK_REPORTER_H_ diff --git a/include/benchmark/state.h b/include/benchmark/state.h new file mode 100644 index 0000000000..e9cdf0571a --- /dev/null +++ b/include/benchmark/state.h @@ -0,0 +1,265 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_STATE_H_ +#define BENCHMARK_STATE_H_ + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251 4324) +#endif + +#include +#include +#include + +#include "benchmark/counter.h" +#include "benchmark/macros.h" +#include "benchmark/statistics.h" +#include "benchmark/types.h" + +namespace benchmark { + +namespace internal { +class BenchmarkInstance; +class ThreadTimer; +class ThreadManager; +class PerfCountersMeasurement; +} // namespace internal + +class ProfilerManager; + +class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { + public: + struct StateIterator; + friend struct StateIterator; + + inline BENCHMARK_ALWAYS_INLINE StateIterator begin(); + inline BENCHMARK_ALWAYS_INLINE StateIterator end(); + + inline bool KeepRunning(); + + inline bool KeepRunningBatch(IterationCount n); + + void PauseTiming(); + + void ResumeTiming(); + + void SkipWithMessage(const std::string& msg); + + void SkipWithError(const std::string& msg); + + bool skipped() const { return internal::NotSkipped != skipped_; } + + bool error_occurred() const { return internal::SkippedWithError == skipped_; } + + void SetIterationTime(double seconds); + + BENCHMARK_ALWAYS_INLINE + void SetBytesProcessed(int64_t bytes) { + counters["bytes_per_second"] = + Counter(static_cast(bytes), Counter::kIsRate, Counter::kIs1024); + } + + BENCHMARK_ALWAYS_INLINE + int64_t bytes_processed() const { + if (counters.find("bytes_per_second") != counters.end()) + return static_cast(counters.at("bytes_per_second")); + return 0; + } + + BENCHMARK_ALWAYS_INLINE + void SetComplexityN(ComplexityN complexity_n) { + complexity_n_ = complexity_n; + } + + BENCHMARK_ALWAYS_INLINE + ComplexityN complexity_length_n() const { return complexity_n_; } + + BENCHMARK_ALWAYS_INLINE + void SetItemsProcessed(int64_t items) { + counters["items_per_second"] = + Counter(static_cast(items), benchmark::Counter::kIsRate); + } + + BENCHMARK_ALWAYS_INLINE + int64_t items_processed() const { + if (counters.find("items_per_second") != counters.end()) + return static_cast(counters.at("items_per_second")); + return 0; + } + + void SetLabel(const std::string& label); + + BENCHMARK_ALWAYS_INLINE + int64_t range(std::size_t pos = 0) const { + assert(range_.size() > pos); + return range_[pos]; + } + + BENCHMARK_DEPRECATED_MSG("use 'range(0)' instead") + int64_t range_x() const { return range(0); } + + BENCHMARK_DEPRECATED_MSG("use 'range(1)' instead") + int64_t range_y() const { return range(1); } + + BENCHMARK_ALWAYS_INLINE + int threads() const { return threads_; } + + BENCHMARK_ALWAYS_INLINE + int thread_index() const { return thread_index_; } + + BENCHMARK_ALWAYS_INLINE + IterationCount iterations() const { + if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) { + return 0; + } + return max_iterations - total_iterations_ + batch_leftover_; + } + + BENCHMARK_ALWAYS_INLINE + std::string name() const { return name_; } + + size_t range_size() const { return range_.size(); } + + private: + IterationCount total_iterations_; + + IterationCount batch_leftover_; + + public: + const IterationCount max_iterations; + + private: + bool started_; + bool finished_; + internal::Skipped skipped_; + + std::vector range_; + + ComplexityN complexity_n_; + + public: + UserCounters counters; + + private: + State(std::string name, IterationCount max_iters, + const std::vector& ranges, int thread_i, int n_threads, + internal::ThreadTimer* timer, internal::ThreadManager* manager, + internal::PerfCountersMeasurement* perf_counters_measurement, + ProfilerManager* profiler_manager); + + void StartKeepRunning(); + inline bool KeepRunningInternal(IterationCount n, bool is_batch); + void FinishKeepRunning(); + + const std::string name_; + const int thread_index_; + const int threads_; + + internal::ThreadTimer* const timer_; + internal::ThreadManager* const manager_; + internal::PerfCountersMeasurement* const perf_counters_measurement_; + ProfilerManager* const profiler_manager_; + + friend class internal::BenchmarkInstance; +}; + +inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunning() { + return KeepRunningInternal(1, /*is_batch=*/false); +} + +inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningBatch(IterationCount n) { + return KeepRunningInternal(n, /*is_batch=*/true); +} + +inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n, + bool is_batch) { + assert(n > 0); + assert(is_batch || n == 1); + if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) { + total_iterations_ -= n; + return true; + } + if (!started_) { + StartKeepRunning(); + if (!skipped() && total_iterations_ >= n) { + total_iterations_ -= n; + return true; + } + } + if (is_batch && total_iterations_ != 0) { + batch_leftover_ = n - total_iterations_; + total_iterations_ = 0; + return true; + } + FinishKeepRunning(); + return false; +} + +struct State::StateIterator { + struct BENCHMARK_UNUSED Value {}; + typedef std::forward_iterator_tag iterator_category; + typedef Value value_type; + typedef Value reference; + typedef Value pointer; + typedef std::ptrdiff_t difference_type; + + private: + friend class State; + BENCHMARK_ALWAYS_INLINE + StateIterator() : cached_(0), parent_() {} + + BENCHMARK_ALWAYS_INLINE + explicit StateIterator(State* st) + : cached_(st->skipped() ? 0 : st->max_iterations), parent_(st) {} + + public: + BENCHMARK_ALWAYS_INLINE + Value operator*() const { return Value(); } + + BENCHMARK_ALWAYS_INLINE + StateIterator& operator++() { + assert(cached_ > 0); + --cached_; + return *this; + } + + BENCHMARK_ALWAYS_INLINE + bool operator!=(StateIterator const&) const { + if (BENCHMARK_BUILTIN_EXPECT(cached_ != 0, true)) return true; + parent_->FinishKeepRunning(); + return false; + } + + private: + IterationCount cached_; + State* const parent_; +}; + +inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::begin() { + return StateIterator(this); +} +inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { + StartKeepRunning(); + return StateIterator(); +} + +} // namespace benchmark + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // BENCHMARK_STATE_H_ diff --git a/include/benchmark/statistics.h b/include/benchmark/statistics.h new file mode 100644 index 0000000000..04f01b151c --- /dev/null +++ b/include/benchmark/statistics.h @@ -0,0 +1,65 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_STATISTICS_H_ +#define BENCHMARK_STATISTICS_H_ + +#include +#include + +#include "benchmark/types.h" + +namespace benchmark { + +enum BigO { oNone, o1, oN, oNSquared, oNCubed, oLogN, oNLogN, oAuto, oLambda }; + +typedef int64_t ComplexityN; + +enum StatisticUnit { kTime, kPercentage }; + +typedef double(BigOFunc)(ComplexityN); + +typedef double(StatisticsFunc)(const std::vector&); + +namespace internal { +struct Statistics { + std::string name_; + StatisticsFunc* compute_; + StatisticUnit unit_; + + Statistics(const std::string& name, StatisticsFunc* compute, + StatisticUnit unit = kTime) + : name_(name), compute_(compute), unit_(unit) {} +}; + +enum AggregationReportMode : unsigned { + ARM_Unspecified = 0, + ARM_Default = 1U << 0U, + ARM_FileReportAggregatesOnly = 1U << 1U, + ARM_DisplayReportAggregatesOnly = 1U << 2U, + ARM_ReportAggregatesOnly = + ARM_FileReportAggregatesOnly | ARM_DisplayReportAggregatesOnly +}; + +enum Skipped : unsigned { + NotSkipped = 0, + SkippedWithMessage, + SkippedWithError +}; + +} // namespace internal + +} // namespace benchmark + +#endif // BENCHMARK_STATISTICS_H_ diff --git a/include/benchmark/sysinfo.h b/include/benchmark/sysinfo.h new file mode 100644 index 0000000000..711e64d7fb --- /dev/null +++ b/include/benchmark/sysinfo.h @@ -0,0 +1,71 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_SYSINFO_H_ +#define BENCHMARK_SYSINFO_H_ + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + +#include +#include + +#include "benchmark/macros.h" + +namespace benchmark { + +struct BENCHMARK_EXPORT CPUInfo { + struct CacheInfo { + std::string type; + int level; + int size; + int num_sharing; + }; + + enum Scaling { UNKNOWN, ENABLED, DISABLED }; + + int num_cpus; + Scaling scaling; + double cycles_per_second; + std::vector caches; + std::vector load_avg; + + static const CPUInfo& Get(); + + private: + CPUInfo(); + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(CPUInfo); +}; + +struct BENCHMARK_EXPORT SystemInfo { + enum class ASLR { UNKNOWN, ENABLED, DISABLED }; + + std::string name; + ASLR ASLRStatus; + static const SystemInfo& Get(); + + private: + SystemInfo(); + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(SystemInfo); +}; + +} // namespace benchmark + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // BENCHMARK_SYSINFO_H_ diff --git a/include/benchmark/types.h b/include/benchmark/types.h new file mode 100644 index 0000000000..a82ffb90cc --- /dev/null +++ b/include/benchmark/types.h @@ -0,0 +1,50 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_TYPES_H_ +#define BENCHMARK_TYPES_H_ + +#include + +#include +#include +#include + +#include "benchmark/export.h" + +namespace benchmark { + +namespace internal { +#if (__cplusplus < 201402L || (defined(_MSC_VER) && _MSVC_LANG < 201402L)) +template +std::unique_ptr make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} +#else +using ::std::make_unique; +#endif +} // namespace internal + +class BenchmarkReporter; +class State; + +using IterationCount = int64_t; + +using callback_function = std::function; + +enum TimeUnit { kNanosecond, kMicrosecond, kMillisecond, kSecond }; + +} // namespace benchmark + +#endif // BENCHMARK_TYPES_H_ diff --git a/include/benchmark/utils.h b/include/benchmark/utils.h new file mode 100644 index 0000000000..2be0d3f02a --- /dev/null +++ b/include/benchmark/utils.h @@ -0,0 +1,152 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_UTILS_H_ +#define BENCHMARK_UTILS_H_ + +#include +#include +#include + +#include "benchmark/macros.h" + +namespace benchmark { + +namespace internal { +BENCHMARK_EXPORT void UseCharPointer(char const volatile*); +} + +#if (!defined(__GNUC__) && !defined(__clang__)) || defined(__pnacl__) || \ + defined(__EMSCRIPTEN__) +#define BENCHMARK_HAS_NO_INLINE_ASSEMBLY +#endif + +inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { + std::atomic_signal_fence(std::memory_order_acq_rel); +} + +#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY +#if !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) +template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + asm volatile("" : : "r,m"(value) : "memory"); +} + +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { +#if defined(__clang__) + asm volatile("" : "+r,m"(value) : : "memory"); +#else + asm volatile("" : "+m,r"(value) : : "memory"); +#endif +} + +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { +#if defined(__clang__) + asm volatile("" : "+r,m"(value) : : "memory"); +#else + asm volatile("" : "+m,r"(value) : : "memory"); +#endif +} +#elif (__GNUC__ >= 5) +template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value && + (sizeof(Tp) <= sizeof(Tp*))>::type + DoNotOptimize(Tp const& value) { + asm volatile("" : : "r,m"(value) : "memory"); +} + +template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value || + (sizeof(Tp) > sizeof(Tp*))>::type + DoNotOptimize(Tp const& value) { + asm volatile("" : : "m"(value) : "memory"); +} + +template +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value && + (sizeof(Tp) <= sizeof(Tp*))>::type + DoNotOptimize(Tp& value) { + asm volatile("" : "+m,r"(value) : : "memory"); +} + +template +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value || + (sizeof(Tp) > sizeof(Tp*))>::type + DoNotOptimize(Tp& value) { + asm volatile("" : "+m"(value) : : "memory"); +} + +template +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value && + (sizeof(Tp) <= sizeof(Tp*))>::type + DoNotOptimize(Tp&& value) { + asm volatile("" : "+m,r"(value) : : "memory"); +} + +template +inline BENCHMARK_ALWAYS_INLINE + typename std::enable_if::value || + (sizeof(Tp) > sizeof(Tp*))>::type + DoNotOptimize(Tp&& value) { + asm volatile("" : "+m"(value) : : "memory"); +} +#endif + +#elif defined(_MSC_VER) +template +BENCHMARK_DEPRECATED_MSG( + "The const-ref version of this method can permit " + "undesired compiler optimizations in benchmarks") +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + internal::UseCharPointer(&reinterpret_cast(value)); + _ReadWriteBarrier(); +} + +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { + internal::UseCharPointer(&reinterpret_cast(value)); + _ReadWriteBarrier(); +} + +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { + internal::UseCharPointer(&reinterpret_cast(value)); + _ReadWriteBarrier(); +} +#else +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { + internal::UseCharPointer(&reinterpret_cast(value)); +} +#endif + +} // end namespace benchmark + +#endif // BENCHMARK_UTILS_H_ diff --git a/src/benchmark.cc b/src/benchmark.cc index fc36fedb19..acf4d3bb10 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -12,8 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "benchmark/benchmark.h" - +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" +#include "benchmark/types.h" #include "benchmark_api_internal.h" #include "benchmark_runner.h" #include "internal_macros.h" diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h index 5b48ea2fdf..0f356da2e7 100644 --- a/src/benchmark_api_internal.h +++ b/src/benchmark_api_internal.h @@ -8,7 +8,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/reporter.h" +#include "benchmark/sysinfo.h" #include "commandlineflags.h" namespace benchmark { diff --git a/src/benchmark_main.cc b/src/benchmark_main.cc index 15c76eaceb..05016439ec 100644 --- a/src/benchmark_main.cc +++ b/src/benchmark_main.cc @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "benchmark/benchmark.h" +#include "benchmark/export.h" +#include "benchmark/registration.h" BENCHMARK_EXPORT int main(int /*argc*/, char** /*argv*/); BENCHMARK_MAIN(); diff --git a/src/benchmark_name.cc b/src/benchmark_name.cc index 804cfbd3b7..710eb6db4b 100644 --- a/src/benchmark_name.cc +++ b/src/benchmark_name.cc @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include "benchmark/export.h" +#include "benchmark/reporter.h" namespace benchmark { diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 65e1afced3..730d275462 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -36,7 +36,11 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/statistics.h" +#include "benchmark/types.h" #include "benchmark_api_internal.h" #include "check.h" #include "commandlineflags.h" diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index fb688672a4..7efbad4e34 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -14,7 +14,11 @@ #include "benchmark_runner.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/managers.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" +#include "benchmark/types.h" #include "benchmark_api_internal.h" #include "internal_macros.h" diff --git a/src/complexity.cc b/src/complexity.cc index 4c9ef6d0c7..8fa3f073af 100644 --- a/src/complexity.cc +++ b/src/complexity.cc @@ -19,7 +19,9 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/reporter.h" +#include "benchmark/statistics.h" +#include "benchmark/types.h" #include "check.h" namespace benchmark { diff --git a/src/complexity.h b/src/complexity.h index 0a0679b48b..06002be215 100644 --- a/src/complexity.h +++ b/src/complexity.h @@ -21,7 +21,8 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/reporter.h" +#include "benchmark/statistics.h" namespace benchmark { diff --git a/src/console_reporter.cc b/src/console_reporter.cc index a7cde4e9b2..84fe99dad1 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -21,7 +21,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/export.h" +#include "benchmark/reporter.h" +#include "benchmark/types.h" #include "check.h" #include "colorprint.h" #include "commandlineflags.h" diff --git a/src/counter.h b/src/counter.h index 1f5a58e31f..811a667a57 100644 --- a/src/counter.h +++ b/src/counter.h @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef BENCHMARK_COUNTER_H_ -#define BENCHMARK_COUNTER_H_ +#ifndef BENCHMARK_SRC_COUNTER_H_ +#define BENCHMARK_SRC_COUNTER_H_ -#include "benchmark/benchmark.h" +#include "benchmark/counter.h" +#include "benchmark/export.h" +#include "benchmark/types.h" namespace benchmark { -// these counter-related functions are hidden to reduce API surface. namespace internal { void Finish(UserCounters* l, IterationCount iterations, double time, double num_threads); @@ -29,4 +30,4 @@ bool SameNames(UserCounters const& l, UserCounters const& r); } // end namespace benchmark -#endif // BENCHMARK_COUNTER_H_ +#endif // BENCHMARK_SRC_COUNTER_H_ diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 0f998045bd..1665ac58ac 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -16,7 +16,8 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/export.h" +#include "benchmark/reporter.h" #include "check.h" #include "complexity.h" diff --git a/src/cycleclock.h b/src/cycleclock.h index 0671a425f0..2633f22b16 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -23,7 +23,7 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/macros.h" #include "internal_macros.h" #if defined(BENCHMARK_OS_MACOSX) diff --git a/src/json_reporter.cc b/src/json_reporter.cc index 2b84cd14a5..ef4636e187 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -22,7 +22,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/export.h" +#include "benchmark/reporter.h" +#include "benchmark/types.h" #include "complexity.h" #include "string_util.h" #include "timers.h" diff --git a/src/perf_counters.h b/src/perf_counters.h index 4e45344318..23cdcc378a 100644 --- a/src/perf_counters.h +++ b/src/perf_counters.h @@ -16,12 +16,15 @@ #define BENCHMARK_PERF_COUNTERS_H #include +#include #include #include #include #include -#include "benchmark/benchmark.h" +#include "benchmark/export.h" +#include "benchmark/macros.h" +#include "benchmark/utils.h" #include "check.h" #include "log.h" #include "mutex.h" diff --git a/src/reporter.cc b/src/reporter.cc index 71926b15e9..73ca8d0d56 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "benchmark/reporter.h" + #include #include #include @@ -19,7 +21,8 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/sysinfo.h" #include "check.h" #include "string_util.h" #include "timers.h" @@ -31,10 +34,10 @@ BenchmarkReporter::BenchmarkReporter() BenchmarkReporter::~BenchmarkReporter() {} -void BenchmarkReporter::PrintBasicContext(std::ostream *out, - Context const &context) { +void BenchmarkReporter::PrintBasicContext(std::ostream* out, + Context const& context) { BM_CHECK(out) << "cannot be null"; - auto &Out = *out; + auto& Out = *out; #ifndef BENCHMARK_OS_QURT // Date/time information is not available on QuRT. @@ -47,13 +50,13 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, << "\n"; } - const CPUInfo &info = context.cpu_info; + const CPUInfo& info = context.cpu_info; Out << "Run on (" << info.num_cpus << " X " << (info.cycles_per_second / 1000000.0) << " MHz CPU " << ((info.num_cpus > 1) ? "s" : "") << ")\n"; if (!info.caches.empty()) { Out << "CPU Caches:\n"; - for (const auto &CInfo : info.caches) { + for (const auto& CInfo : info.caches) { Out << " L" << CInfo.level << " " << CInfo.type << " " << (CInfo.size / 1024) << " KiB"; if (CInfo.num_sharing != 0) { @@ -73,11 +76,11 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, Out << "\n"; } - std::map *global_context = + std::map* global_context = internal::GetGlobalContext(); if (global_context != nullptr) { - for (const auto &kv : *global_context) { + for (const auto& kv : *global_context) { Out << kv.first << ": " << kv.second << "\n"; } } @@ -88,7 +91,7 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, "overhead.\n"; } - const SystemInfo &sysinfo = context.sys_info; + const SystemInfo& sysinfo = context.sys_info; if (SystemInfo::ASLR::ENABLED == sysinfo.ASLRStatus) { Out << "***WARNING*** ASLR is enabled, the results may have unreproducible " "noise in them.\n"; @@ -101,7 +104,7 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out, } // No initializer because it's already initialized to NULL. -const char *BenchmarkReporter::Context::executable_name; +const char* BenchmarkReporter::Context::executable_name; BenchmarkReporter::Context::Context() : cpu_info(CPUInfo::Get()), sys_info(SystemInfo::Get()) {} diff --git a/src/statistics.cc b/src/statistics.cc index fc7450ef91..2c6c8584ab 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -21,7 +21,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/reporter.h" +#include "benchmark/statistics.h" +#include "benchmark/types.h" #include "check.h" namespace benchmark { diff --git a/src/statistics.h b/src/statistics.h index 6e5560e8f1..2e56c53608 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -18,7 +18,8 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/export.h" +#include "benchmark/reporter.h" namespace benchmark { diff --git a/src/string_util.cc b/src/string_util.cc index aa36cf949a..ae9667bd2d 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -11,7 +11,7 @@ #include #include "arraysize.h" -#include "benchmark/benchmark.h" +#include "benchmark/types.h" namespace benchmark { namespace { diff --git a/src/string_util.h b/src/string_util.h index 7a2ce0ba79..1a846668ba 100644 --- a/src/string_util.h +++ b/src/string_util.h @@ -6,7 +6,7 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/counter.h" #include "benchmark/export.h" #include "check.h" diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 3977772bfe..12a09cfb13 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -77,7 +77,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/export.h" +#include "benchmark/sysinfo.h" +#include "benchmark/utils.h" #include "check.h" #include "cycleclock.h" #include "log.h" diff --git a/src/thread_manager.h b/src/thread_manager.h index a0ac37a8b2..80252b6117 100644 --- a/src/thread_manager.h +++ b/src/thread_manager.h @@ -3,7 +3,9 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/counter.h" +#include "benchmark/statistics.h" +#include "benchmark/types.h" #include "mutex.h" namespace benchmark { diff --git a/test/args_product_test.cc b/test/args_product_test.cc index 63b8b71e45..5dbcc21683 100644 --- a/test/args_product_test.cc +++ b/test/args_product_test.cc @@ -3,7 +3,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" class ArgsProductFixture : public ::benchmark::Fixture { public: diff --git a/test/basic_test.cc b/test/basic_test.cc index 068cd98476..e1db1cb02f 100644 --- a/test/basic_test.cc +++ b/test/basic_test.cc @@ -1,5 +1,8 @@ -#include "benchmark/benchmark.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/types.h" +#include "benchmark/utils.h" #define BASIC_BENCHMARK_TEST(x) BENCHMARK(x)->Arg(8)->Arg(512)->Arg(8192) diff --git a/test/benchmark_gtest.cc b/test/benchmark_gtest.cc index 0aa2552c1e..09d7c80a25 100644 --- a/test/benchmark_gtest.cc +++ b/test/benchmark_gtest.cc @@ -3,7 +3,7 @@ #include #include "../src/benchmark_register.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -136,7 +136,7 @@ TEST(AddRangeTest, Simple8) { } TEST(AddCustomContext, Simple) { - std::map *&global_context = GetGlobalContext(); + std::map*& global_context = GetGlobalContext(); EXPECT_THAT(global_context, nullptr); AddCustomContext("foo", "bar"); @@ -151,7 +151,7 @@ TEST(AddCustomContext, Simple) { } TEST(AddCustomContext, DuplicateKey) { - std::map *&global_context = GetGlobalContext(); + std::map*& global_context = GetGlobalContext(); EXPECT_THAT(global_context, nullptr); AddCustomContext("foo", "bar"); diff --git a/test/benchmark_min_time_flag_iters_test.cc b/test/benchmark_min_time_flag_iters_test.cc index dedcbe6fa3..3866ac045b 100644 --- a/test/benchmark_min_time_flag_iters_test.cc +++ b/test/benchmark_min_time_flag_iters_test.cc @@ -4,7 +4,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" // Tests that we can specify the number of iterations with // --benchmark_min_time=x. diff --git a/test/benchmark_min_time_flag_time_test.cc b/test/benchmark_min_time_flag_time_test.cc index bbc2cc35d8..2e8f52fc67 100644 --- a/test/benchmark_min_time_flag_time_test.cc +++ b/test/benchmark_min_time_flag_time_test.cc @@ -7,7 +7,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" // Tests that we can specify the min time with // --benchmark_min_time= (no suffix needed) OR diff --git a/test/benchmark_name_gtest.cc b/test/benchmark_name_gtest.cc index 0a6746d04d..34e97b07a3 100644 --- a/test/benchmark_name_gtest.cc +++ b/test/benchmark_name_gtest.cc @@ -1,4 +1,4 @@ -#include "benchmark/benchmark.h" +#include "benchmark/reporter.h" #include "gtest/gtest.h" namespace { diff --git a/test/benchmark_random_interleaving_gtest.cc b/test/benchmark_random_interleaving_gtest.cc index 5f3a554743..cb7f668ff5 100644 --- a/test/benchmark_random_interleaving_gtest.cc +++ b/test/benchmark_random_interleaving_gtest.cc @@ -4,7 +4,10 @@ #include "../src/commandlineflags.h" #include "../src/string_util.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/test/benchmark_setup_teardown_cb_types_gtest.cc b/test/benchmark_setup_teardown_cb_types_gtest.cc index 2ed255dcd3..716b722b68 100644 --- a/test/benchmark_setup_teardown_cb_types_gtest.cc +++ b/test/benchmark_setup_teardown_cb_types_gtest.cc @@ -1,4 +1,7 @@ -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" +#include "benchmark/types.h" #include "gtest/gtest.h" using benchmark::Benchmark; diff --git a/test/benchmark_setup_teardown_test.cc b/test/benchmark_setup_teardown_test.cc index eb45a73e92..52d2761815 100644 --- a/test/benchmark_setup_teardown_test.cc +++ b/test/benchmark_setup_teardown_test.cc @@ -4,7 +4,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" // Test that Setup() and Teardown() are called exactly once // for each benchmark run (single-threaded). diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc index 49cbfba6f3..b98fbdfe35 100644 --- a/test/benchmark_test.cc +++ b/test/benchmark_test.cc @@ -1,5 +1,3 @@ -#include "benchmark/benchmark.h" - #include #include #include @@ -19,6 +17,10 @@ #include #include +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" + #if defined(__GNUC__) #define BENCHMARK_NOINLINE __attribute__((noinline)) #else diff --git a/test/clobber_memory_assembly_test.cc b/test/clobber_memory_assembly_test.cc index 54e26ccdad..24e06660e4 100644 --- a/test/clobber_memory_assembly_test.cc +++ b/test/clobber_memory_assembly_test.cc @@ -1,4 +1,5 @@ -#include +#include "benchmark/macros.h" +#include "benchmark/utils.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Wreturn-type" diff --git a/test/complexity_test.cc b/test/complexity_test.cc index 8cf17f41d3..64a7e72a6d 100644 --- a/test/complexity_test.cc +++ b/test/complexity_test.cc @@ -4,7 +4,12 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/statistics.h" +#include "benchmark/types.h" +#include "benchmark/utils.h" #include "output_test.h" namespace { diff --git a/test/cxx11_test.cc b/test/cxx11_test.cc index db1a993343..a2e8bc895f 100644 --- a/test/cxx11_test.cc +++ b/test/cxx11_test.cc @@ -1,4 +1,4 @@ -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" #if defined(_MSC_VER) #if _MSVC_LANG != 201402L diff --git a/test/diagnostics_test.cc b/test/diagnostics_test.cc index e8d7d9119a..a79e49f49c 100644 --- a/test/diagnostics_test.cc +++ b/test/diagnostics_test.cc @@ -11,7 +11,10 @@ #include #include "../src/check.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #if defined(__GNUC__) && !defined(__EXCEPTIONS) #define TEST_HAS_NO_EXCEPTIONS diff --git a/test/display_aggregates_only_test.cc b/test/display_aggregates_only_test.cc index bae97593ac..86f202fe5b 100644 --- a/test/display_aggregates_only_test.cc +++ b/test/display_aggregates_only_test.cc @@ -3,7 +3,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" #include "output_test.h" // Ok this test is super ugly. We want to check what happens with the file diff --git a/test/donotoptimize_assembly_test.cc b/test/donotoptimize_assembly_test.cc index 1f817e02bb..d7b3b549d2 100644 --- a/test/donotoptimize_assembly_test.cc +++ b/test/donotoptimize_assembly_test.cc @@ -1,4 +1,5 @@ -#include +#include "benchmark/macros.h" +#include "benchmark/utils.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Wreturn-type" diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc index 7571cf445e..34b1ed6479 100644 --- a/test/donotoptimize_test.cc +++ b/test/donotoptimize_test.cc @@ -1,6 +1,7 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/utils.h" namespace { #if defined(__GNUC__) diff --git a/test/filter_test.cc b/test/filter_test.cc index 8c150eb2de..bcbf2ff6de 100644 --- a/test/filter_test.cc +++ b/test/filter_test.cc @@ -8,7 +8,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" namespace { diff --git a/test/fixture_test.cc b/test/fixture_test.cc index d1093ebf52..8994dee1c1 100644 --- a/test/fixture_test.cc +++ b/test/fixture_test.cc @@ -2,7 +2,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" #define FIXTURE_BECHMARK_NAME MyFixture diff --git a/test/internal_threading_test.cc b/test/internal_threading_test.cc index c57bf44b0c..4d1dd1b711 100644 --- a/test/internal_threading_test.cc +++ b/test/internal_threading_test.cc @@ -5,7 +5,10 @@ #include #include "../src/timers.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/counter.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" #include "output_test.h" namespace { diff --git a/test/link_main_test.cc b/test/link_main_test.cc index 41dbac9ab0..538f807020 100644 --- a/test/link_main_test.cc +++ b/test/link_main_test.cc @@ -1,4 +1,6 @@ -#include "benchmark/benchmark.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" namespace { void BM_empty(benchmark::State& state) { diff --git a/test/locale_impermeability_test.cc b/test/locale_impermeability_test.cc index e2dd6cfd9d..0776fe6114 100644 --- a/test/locale_impermeability_test.cc +++ b/test/locale_impermeability_test.cc @@ -3,7 +3,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" #include "output_test.h" namespace { diff --git a/test/manual_threading_test.cc b/test/manual_threading_test.cc index b3252ec16e..bac36bce95 100644 --- a/test/manual_threading_test.cc +++ b/test/manual_threading_test.cc @@ -6,7 +6,10 @@ #include #include "../src/timers.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/counter.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" namespace { diff --git a/test/map_test.cc b/test/map_test.cc index 018e12a75e..f4b41d2a07 100644 --- a/test/map_test.cc +++ b/test/map_test.cc @@ -1,7 +1,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" namespace { diff --git a/test/memory_manager_test.cc b/test/memory_manager_test.cc index 39b32169d5..36de9d4ca2 100644 --- a/test/memory_manager_test.cc +++ b/test/memory_manager_test.cc @@ -1,6 +1,10 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/managers.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #include "output_test.h" namespace { diff --git a/test/memory_results_gtest.cc b/test/memory_results_gtest.cc index 70a5a5a985..f856fbf67b 100644 --- a/test/memory_results_gtest.cc +++ b/test/memory_results_gtest.cc @@ -1,6 +1,9 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/managers.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" #include "gtest/gtest.h" namespace { diff --git a/test/multiple_ranges_test.cc b/test/multiple_ranges_test.cc index 987b69c82f..695b52a9e1 100644 --- a/test/multiple_ranges_test.cc +++ b/test/multiple_ranges_test.cc @@ -3,7 +3,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" namespace { class MultipleRangesFixture : public ::benchmark::Fixture { diff --git a/test/options_test.cc b/test/options_test.cc index 70e3e18e2f..7ace93364b 100644 --- a/test/options_test.cc +++ b/test/options_test.cc @@ -1,7 +1,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/types.h" #if defined(NDEBUG) #undef NDEBUG diff --git a/test/output_test.h b/test/output_test.h index 0fd557d90b..9337edc07a 100644 --- a/test/output_test.h +++ b/test/output_test.h @@ -11,7 +11,7 @@ #include #include "../src/re.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" #define CONCAT2(x, y) x##y #define CONCAT(x, y) CONCAT2(x, y) diff --git a/test/overload_test.cc b/test/overload_test.cc index d1fee9a783..0a62b78605 100644 --- a/test/overload_test.cc +++ b/test/overload_test.cc @@ -1,4 +1,6 @@ -#include "benchmark/benchmark.h" +#include "benchmark/macros.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" namespace { // Simulate an overloaded function name. diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index a830b5ef10..d97fa37ec9 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -3,7 +3,10 @@ #include "../src/commandlineflags.h" #include "../src/perf_counters.h" -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #include "output_test.h" namespace benchmark { diff --git a/test/profiler_manager_gtest.cc b/test/profiler_manager_gtest.cc index 434e4ecadf..6e83e32a90 100644 --- a/test/profiler_manager_gtest.cc +++ b/test/profiler_manager_gtest.cc @@ -1,6 +1,9 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/managers.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #include "gtest/gtest.h" namespace { diff --git a/test/profiler_manager_iterations_test.cc b/test/profiler_manager_iterations_test.cc index c4983eb348..90b34a1daa 100644 --- a/test/profiler_manager_iterations_test.cc +++ b/test/profiler_manager_iterations_test.cc @@ -3,7 +3,11 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/managers.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" // Tests that we can specify the number of profiler iterations with // --benchmark_min_time=x. diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc index 5c4b14daa3..bd86d42c04 100644 --- a/test/profiler_manager_test.cc +++ b/test/profiler_manager_test.cc @@ -3,7 +3,11 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/managers.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #include "output_test.h" namespace { diff --git a/test/register_benchmark_test.cc b/test/register_benchmark_test.cc index 0ebd8f32d9..c662d494b4 100644 --- a/test/register_benchmark_test.cc +++ b/test/register_benchmark_test.cc @@ -4,7 +4,10 @@ #include #include "../src/check.h" // NOTE: check.h is for internal use only! -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" namespace { diff --git a/test/repetitions_test.cc b/test/repetitions_test.cc index 9116fa65be..80216ab4e1 100644 --- a/test/repetitions_test.cc +++ b/test/repetitions_test.cc @@ -1,5 +1,7 @@ -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" #include "output_test.h" namespace { diff --git a/test/report_aggregates_only_test.cc b/test/report_aggregates_only_test.cc index 707d92383a..cb0ad09b04 100644 --- a/test/report_aggregates_only_test.cc +++ b/test/report_aggregates_only_test.cc @@ -3,7 +3,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" #include "output_test.h" namespace { diff --git a/test/reporter_output_test.cc b/test/reporter_output_test.cc index 9940ab75de..26d87de012 100644 --- a/test/reporter_output_test.cc +++ b/test/reporter_output_test.cc @@ -1,6 +1,12 @@ #undef NDEBUG -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/statistics.h" +#include "benchmark/sysinfo.h" +#include "benchmark/types.h" +#include "benchmark/utils.h" #include "output_test.h" namespace { diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc index 425895988c..d30c23e627 100644 --- a/test/skip_with_error_test.cc +++ b/test/skip_with_error_test.cc @@ -4,7 +4,11 @@ #include #include "../src/check.h" // NOTE: check.h is for internal use only! -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" namespace { diff --git a/test/spec_arg_test.cc b/test/spec_arg_test.cc index 21275ef0d8..393eca52f5 100644 --- a/test/spec_arg_test.cc +++ b/test/spec_arg_test.cc @@ -8,7 +8,10 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/reporter.h" +#include "benchmark/state.h" // Tests that we can override benchmark-spec value from FLAGS_benchmark_filter // with argument to RunSpecifiedBenchmarks(...). diff --git a/test/spec_arg_verbosity_test.cc b/test/spec_arg_verbosity_test.cc index 318784cfff..49aadd9f37 100644 --- a/test/spec_arg_verbosity_test.cc +++ b/test/spec_arg_verbosity_test.cc @@ -2,7 +2,9 @@ #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" namespace { // Tests that the user specified verbosity level can be get. diff --git a/test/state_assembly_test.cc b/test/state_assembly_test.cc index e9ecfebf16..5efceedd9e 100644 --- a/test/state_assembly_test.cc +++ b/test/state_assembly_test.cc @@ -1,4 +1,5 @@ -#include +#include "benchmark/state.h" +#include "benchmark/utils.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Wreturn-type" diff --git a/test/templated_fixture_method_test.cc b/test/templated_fixture_method_test.cc index 06fc7d83e7..3de726baa1 100644 --- a/test/templated_fixture_method_test.cc +++ b/test/templated_fixture_method_test.cc @@ -2,7 +2,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" template class MyFixture : public ::benchmark::Fixture { diff --git a/test/templated_fixture_test.cc b/test/templated_fixture_test.cc index af239c3a72..44108dda9c 100644 --- a/test/templated_fixture_test.cc +++ b/test/templated_fixture_test.cc @@ -2,7 +2,9 @@ #include #include -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" template class MyFixture : public ::benchmark::Fixture { diff --git a/test/time_unit_gtest.cc b/test/time_unit_gtest.cc index 0da11092b7..1d4d2d086c 100644 --- a/test/time_unit_gtest.cc +++ b/test/time_unit_gtest.cc @@ -1,4 +1,5 @@ -#include "../include/benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/state.h" #include "gtest/gtest.h" namespace benchmark { diff --git a/test/user_counters_tabular_test.cc b/test/user_counters_tabular_test.cc index 7db0e20822..f173f1ba1d 100644 --- a/test/user_counters_tabular_test.cc +++ b/test/user_counters_tabular_test.cc @@ -1,7 +1,11 @@ #undef NDEBUG -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/counter.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #include "output_test.h" namespace { diff --git a/test/user_counters_test.cc b/test/user_counters_test.cc index a8af0877cc..9253d594f3 100644 --- a/test/user_counters_test.cc +++ b/test/user_counters_test.cc @@ -1,7 +1,11 @@ #undef NDEBUG -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/counter.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #include "output_test.h" // ========================================================================= // diff --git a/test/user_counters_thousands_test.cc b/test/user_counters_thousands_test.cc index 0ef78d3787..58170e98b9 100644 --- a/test/user_counters_thousands_test.cc +++ b/test/user_counters_thousands_test.cc @@ -1,7 +1,10 @@ #undef NDEBUG -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/counter.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" #include "output_test.h" namespace { diff --git a/test/user_counters_threads_test.cc b/test/user_counters_threads_test.cc index e2e5ade460..9fd01a646c 100644 --- a/test/user_counters_threads_test.cc +++ b/test/user_counters_threads_test.cc @@ -1,7 +1,10 @@ #undef NDEBUG -#include "benchmark/benchmark.h" +#include "benchmark/benchmark_api.h" +#include "benchmark/registration.h" +#include "benchmark/state.h" +#include "benchmark/utils.h" #include "output_test.h" // ========================================================================= // From fae322baa7c141f3728086b2158710b54e982658 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 5 Mar 2026 10:53:11 +0000 Subject: [PATCH 476/561] refactor ToExponentAndMantissa to use StrFormat instead of std::stringstream (#2138) * perf: refactor ToExponentAndMantissa to use StrFormat instead of std::stringstream * return pair instead of using output parameters * Bump astral-sh/setup-uv from 7.3.0 to 7.3.1 (#2136) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.3.0 to 7.3.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/eac588ad8def6316056a12d4907a9d4d84ff7a3b...5a095e7a2014a4212f075830d4f7277575a9d098) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> * lambda for mantissa formatting * structured bindings and clearer code structure * multiple fixes to avoid Windows x64 crashes (#2139) * fix: cast size_t widths to int for variadic printer to avoid Windows x64 crashes * extend minimum time as Windows can have a coarse timer * vsnprintf can consume va_list so we need to copy it to avoid UB * extend longer test runtime to other problematic tests --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/string_util.cc | 61 ++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/string_util.cc b/src/string_util.cc index ae9667bd2d..9a0d54234c 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -31,13 +31,15 @@ static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits), const int64_t kUnitsSize = arraysize(kBigSIUnits); -void ToExponentAndMantissa(double val, int precision, double one_k, - std::string* mantissa, int64_t* exponent) { - std::stringstream mantissa_stream; - +std::pair ToExponentAndMantissa(double val, int precision, + double one_k) { + std::string mantissa; + int64_t exponent = 0; if (val < 0) { - mantissa_stream << "-"; + mantissa = "-"; val = -val; + } else { + mantissa.clear(); } // Adjust threshold so that it never excludes things which can't be rendered @@ -49,41 +51,45 @@ void ToExponentAndMantissa(double val, int precision, double one_k, // Values in ]simple_threshold,small_threshold[ will be printed as-is const double simple_threshold = 0.01; + auto format_mantissa = [&](double v) { mantissa += StrFormat("%g", v); }; + + // Positive powers if (val > big_threshold) { - // Positive powers double scaled = val; for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) { scaled /= one_k; if (scaled <= big_threshold) { - mantissa_stream << scaled; - *exponent = static_cast(i + 1); - *mantissa = mantissa_stream.str(); - return; + format_mantissa(scaled); + exponent = static_cast(i + 1); + return std::make_pair(mantissa, exponent); } } - mantissa_stream << val; - *exponent = 0; - } else if (val < small_threshold) { - // Negative powers + format_mantissa(val); + exponent = 0; + return std::make_pair(mantissa, exponent); + } + + // Negative powers + if (val < small_threshold) { if (val < simple_threshold) { double scaled = val; for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) { scaled *= one_k; if (scaled >= small_threshold) { - mantissa_stream << scaled; - *exponent = -static_cast(i + 1); - *mantissa = mantissa_stream.str(); - return; + format_mantissa(scaled); + exponent = -static_cast(i + 1); + return std::make_pair(mantissa, exponent); } } } - mantissa_stream << val; - *exponent = 0; - } else { - mantissa_stream << val; - *exponent = 0; + format_mantissa(val); + exponent = 0; + return std::make_pair(mantissa, exponent); } - *mantissa = mantissa_stream.str(); + + format_mantissa(val); + exponent = 0; + return std::make_pair(mantissa, exponent); } std::string ExponentToPrefix(int64_t exponent, bool iec) { @@ -104,11 +110,8 @@ std::string ExponentToPrefix(int64_t exponent, bool iec) { std::string ToBinaryStringFullySpecified(double value, int precision, Counter::OneK one_k) { - std::string mantissa; - int64_t exponent = 0; - ToExponentAndMantissa(value, precision, - one_k == Counter::kIs1024 ? 1024.0 : 1000.0, &mantissa, - &exponent); + auto [mantissa, exponent] = ToExponentAndMantissa( + value, precision, one_k == Counter::kIs1024 ? 1024.0 : 1000.0); return mantissa + ExponentToPrefix(exponent, one_k == Counter::kIs1024); } From 1a54956777ba672764db09a51960056ea042af7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 09:27:15 +0000 Subject: [PATCH 477/561] Bump pypa/cibuildwheel from 3.3.1 to 3.4.0 (#2142) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.3.1 to 3.4.0. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e...ee02a1537ce3071a004a6b08c41e72f0fdc42d9a) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 5d3f252445..827c72426d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e # v3.3.1 + uses: pypa/cibuildwheel@ee02a1537ce3071a004a6b08c41e72f0fdc42d9a # v3.4.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From 56ff6a8bd74dd96dca14b2a6013d6df8bffcaad3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 08:58:46 +0000 Subject: [PATCH 478/561] Bump numpy from 2.4.2 to 2.4.3 in /tools (#2143) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.2 to 2.4.3. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.2...v2.4.3) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index b2ef85c1b3..e46989259f 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.4.2 +numpy == 2.4.3 scipy == 1.17.1 From f239b0567a58f1180bb130d38430e33a20b6fbbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 09:09:00 +0000 Subject: [PATCH 479/561] Bump astral-sh/setup-uv from 7.3.1 to 7.4.0 (#2145) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.3.1 to 7.4.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/5a095e7a2014a4212f075830d4f7277575a9d098...6ee6290f1cbc4156c0bdd66691b2c144ef8df19a) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 7d56c28246..ec74788744 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1 + uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7.4.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 827c72426d..20abda29a9 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1 + uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7.4.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@ee02a1537ce3071a004a6b08c41e72f0fdc42d9a # v3.4.0 From a51e54b4fddadc8681fce8047288b14b4a4856be Mon Sep 17 00:00:00 2001 From: aokblast Date: Thu, 12 Mar 2026 02:50:21 +0800 Subject: [PATCH 480/561] Fix CMake detection on pthread_affinity test on FreeBSD (#2146) * Fix cmake detection on pthread_affinity test on FreeBSD In FreeBSD, non posix thread functions locate in the pthread_np.h. We check the platform and include the correct header. Also, pthread related features in some platforms require link to special library. We append Threads target to BENCHMARK_CXX_LIBRARIES so that it can be added by cxx_feature_check. * fixup! Fix cmake detection on pthread_affinity test on FreeBSD --------- Co-authored-by: Roman Lebedev --- CMakeLists.txt | 6 ++++++ CONTRIBUTORS | 1 + cmake/pthread_affinity.cpp | 3 +++ src/CMakeLists.txt | 3 --- src/sysinfo.cc | 3 +++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11d24961c6..254fd3742c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -331,6 +331,12 @@ cxx_feature_check(STEADY_CLOCK) # Ensure we have pthreads set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) + +# cxx_feature_check relies on try_run to probe compiler features. Because this +# check does not produce a real target, target_link_libraries cannot be applied. +# Therefore, link libraries are forwarded to try_run through +# BENCHMARK_CXX_LIBRARIES. +list(APPEND BENCHMARK_CXX_LIBRARIES Threads::Threads) cxx_feature_check(PTHREAD_AFFINITY) if (BENCHMARK_ENABLE_LIBPFM) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 447e720188..a88240c60b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -93,6 +93,7 @@ Robert Guo Roman Lebedev Sayan Bhattacharjee Shashank Thakur +ShengYi Hung Shuo Chen Steven Wan Tobias Schmidt diff --git a/cmake/pthread_affinity.cpp b/cmake/pthread_affinity.cpp index 7b143bc021..2eea573130 100644 --- a/cmake/pthread_affinity.cpp +++ b/cmake/pthread_affinity.cpp @@ -1,4 +1,7 @@ #include +#ifdef __FreeBSD__ +#include +#endif int main() { cpu_set_t set; CPU_ZERO(&set); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e5db4115e..4696594a24 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,9 +49,6 @@ if(HAVE_PTHREAD_AFFINITY) target_compile_definitions(benchmark PRIVATE -DBENCHMARK_HAS_PTHREAD_AFFINITY) endif() -# Link threads. -target_link_libraries(benchmark PRIVATE Threads::Threads) - target_link_libraries(benchmark PRIVATE ${BENCHMARK_CXX_LIBRARIES}) if(HAVE_LIB_RT) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 12a09cfb13..39da0fe217 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -51,6 +51,9 @@ #include #endif #if defined(BENCHMARK_HAS_PTHREAD_AFFINITY) +#if defined(BENCHMARK_OS_FREEBSD) +#include +#endif #include #endif From 25a64324f0b884ab11e2b1df538c2f3bc5d0da1a Mon Sep 17 00:00:00 2001 From: Ash Vardanian <1983160+ashvardanian@users.noreply.github.com> Date: Thu, 12 Mar 2026 10:28:36 +0000 Subject: [PATCH 481/561] Add WASI compatibility (#2144) * Detect non-Emscripten WASI builds * Guard clocks & system APIs google#1774 Co-authored-by: Roman Lebedev --- src/benchmark.cc | 3 ++- src/benchmark_register.cc | 3 ++- src/benchmark_runner.cc | 3 ++- src/cycleclock.h | 2 +- src/internal_macros.h | 2 ++ src/sysinfo.cc | 8 ++++++-- src/timers.cc | 17 +++++++++++++++-- 7 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index acf4d3bb10..e866d296dc 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -22,7 +22,8 @@ #include "internal_macros.h" #ifndef BENCHMARK_OS_WINDOWS -#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) && \ + !defined(BENCHMARK_OS_WASI) #include #endif #include diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc index 730d275462..560a762e9b 100644 --- a/src/benchmark_register.cc +++ b/src/benchmark_register.cc @@ -15,7 +15,8 @@ #include "benchmark_register.h" #ifndef BENCHMARK_OS_WINDOWS -#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) && \ + !defined(BENCHMARK_OS_WASI) #include #endif #include diff --git a/src/benchmark_runner.cc b/src/benchmark_runner.cc index 7efbad4e34..f6d37e0172 100644 --- a/src/benchmark_runner.cc +++ b/src/benchmark_runner.cc @@ -23,7 +23,8 @@ #include "internal_macros.h" #ifndef BENCHMARK_OS_WINDOWS -#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) && \ + !defined(BENCHMARK_OS_WASI) #include #endif #include diff --git a/src/cycleclock.h b/src/cycleclock.h index 2633f22b16..23d67d738a 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -235,7 +235,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { struct timeval tv; gettimeofday(&tv, nullptr); return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; -#elif defined(__hppa__) || defined(__linux__) +#elif defined(__hppa__) || defined(__linux__) || defined(BENCHMARK_OS_WASI) // Fallback for all other architectures with a recent Linux kernel, e.g.: // HP PA-RISC provides a user-readable clock counter (cr16), but // it's not syncronized across CPUs and only 32-bit wide when programs diff --git a/src/internal_macros.h b/src/internal_macros.h index 22e3e21753..a0bd0e1447 100644 --- a/src/internal_macros.h +++ b/src/internal_macros.h @@ -77,6 +77,8 @@ #define BENCHMARK_OS_NACL 1 #elif defined(__EMSCRIPTEN__) #define BENCHMARK_OS_EMSCRIPTEN 1 +#elif defined(__wasi__) + #define BENCHMARK_OS_WASI 1 #elif defined(__rtems__) #define BENCHMARK_OS_RTEMS 1 #elif defined(__Fuchsia__) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index 39da0fe217..ca32daab5a 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -27,7 +27,8 @@ #include #else #include -#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) && \ + !defined(BENCHMARK_OS_WASI) #include #endif #include @@ -444,7 +445,8 @@ std::vector GetCacheSizes() { return GetCacheSizesWindows(); #elif defined(BENCHMARK_OS_QNX) return GetCacheSizesQNX(); -#elif defined(BENCHMARK_OS_QURT) || defined(__EMSCRIPTEN__) +#elif defined(BENCHMARK_OS_QURT) || defined(BENCHMARK_OS_EMSCRIPTEN) || \ + defined(BENCHMARK_OS_WASI) return std::vector(); #else return GetCacheSizesFromKVFS(); @@ -477,6 +479,8 @@ std::string GetSystemName() { str += std::to_string(arch_version_struct.arch_version); } return str; +#elif defined(BENCHMARK_OS_WASI) + return std::string("wasi"); #else #ifndef HOST_NAME_MAX #ifdef BENCHMARK_HAS_SYSCTL // BSD/Mac doesn't have HOST_NAME_MAX defined diff --git a/src/timers.cc b/src/timers.cc index f8d9560ed1..53cf4875e1 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -23,7 +23,8 @@ #include #else #include -#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) +#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) && \ + !defined(BENCHMARK_OS_WASI) #include #endif #include @@ -84,7 +85,8 @@ double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) { static_cast(user.QuadPart)) * 1e-7; } -#elif !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) +#elif !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT) && \ + !defined(BENCHMARK_OS_WASI) double MakeTime(struct rusage const& ru) { return (static_cast(ru.ru_utime.tv_sec) + static_cast(ru.ru_utime.tv_usec) * 1e-6 + @@ -140,6 +142,14 @@ double ProcessCPUUsage() { // same as total time, but this is ok because there aren't long-latency // synchronous system calls in Emscripten. return emscripten_get_now() * 1e-3; +#elif defined(BENCHMARK_OS_WASI) + // WASI lacks CLOCK_PROCESS_CPUTIME_ID and getrusage; use monotonic clock. + struct timespec ts {}; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + return static_cast(ts.tv_sec) + + (static_cast(ts.tv_nsec) * 1e-9); + } + DiagnoseAndExit("clock_gettime(CLOCK_MONOTONIC, ...) failed"); #elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX) // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. // See https://github.com/google/benchmark/pull/292 @@ -195,6 +205,9 @@ double ThreadCPUUsage() { #elif defined(BENCHMARK_OS_ZOS) // z/OS doesn't support CLOCK_THREAD_CPUTIME_ID. return ProcessCPUUsage(); +#elif defined(BENCHMARK_OS_WASI) + // WASI doesn't support per-thread CPU timing; fall back to process time. + return ProcessCPUUsage(); #elif defined(BENCHMARK_OS_SOLARIS) struct rusage ru; if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru); From ed9d1151bf101d0387a81dfc331785cf600e6406 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 10:38:28 +0000 Subject: [PATCH 482/561] Bump actions/download-artifact from 8.0.0 to 8.0.1 (#2147) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 20abda29a9..a7be57c3ef 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -76,7 +76,7 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: dist pattern: dist-* From b893ddfc01c0fd9ebc537e24b194f85c54ff4cbf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:20:48 +0000 Subject: [PATCH 483/561] Bump astral-sh/setup-uv from 7.4.0 to 7.5.0 (#2148) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.4.0 to 7.5.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/6ee6290f1cbc4156c0bdd66691b2c144ef8df19a...e06108dd0aef18192324c70427afc47652e63a82) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index ec74788744..164c84609e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7.4.0 + uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index a7be57c3ef..0e20699759 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7.4.0 + uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@ee02a1537ce3071a004a6b08c41e72f0fdc42d9a # v3.4.0 From 7ea443b55aee9c4efe87067de047ba51f8f27aad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 23:44:41 +0300 Subject: [PATCH 484/561] Bump astral-sh/setup-uv from 7.5.0 to 7.6.0 (#2150) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.5.0 to 7.6.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/e06108dd0aef18192324c70427afc47652e63a82...37802adc94f370d6bfd71619e3f0bf239e1f3b78) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 164c84609e..dae8833c1c 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 0e20699759..7627f011c1 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@ee02a1537ce3071a004a6b08c41e72f0fdc42d9a # v3.4.0 From 70915a0b90bae291350fdbacc719f11511c27f9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 09:09:51 +0000 Subject: [PATCH 485/561] Bump lukka/get-cmake from 4.2.3 to 4.3.0 (#2152) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.2.3 to 4.3.0. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/f176ccd3f28bda569c43aae4894f06b2435a3375...b78306120111dc2522750771cfd09ee7ca723687) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 72d9e7d3a1..2a2ad3e58a 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@f176ccd3f28bda569c43aae4894f06b2435a3375 # latest + - uses: lukka/get-cmake@b78306120111dc2522750771cfd09ee7ca723687 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e3ea001390..06a715b0dc 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@f176ccd3f28bda569c43aae4894f06b2435a3375 # latest + - uses: lukka/get-cmake@b78306120111dc2522750771cfd09ee7ca723687 # latest - name: configure cmake run: > From d4393d5445b4ffa7e0282285dc203923238423da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 09:16:52 +0000 Subject: [PATCH 486/561] Bump actions/cache from 5.0.3 to 5.0.4 (#2151) Bumps [actions/cache](https://github.com/actions/cache) from 5.0.3 to 5.0.4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/cdf6c1fa76f9f475f3d7449005a359c84ca0f306...668228422ae6a00e4ad889ee87cd7109ec5666a7) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index aab9aebd2f..5e5b779475 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: mount bazel cache - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 env: cache-name: bazel-cache with: From 7e413be55370f0f4567761fe71ea8232d6871d06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 23:45:31 +0300 Subject: [PATCH 487/561] Bump msys2/setup-msys2 from 2.30.0 to 2.31.0 (#2153) Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.30.0 to 2.31.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/4f806de0a5a7294ffabaff804b38a9b435a73bda...cafece8e6baf9247cf9b1bf95097b0b983cc558d) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.31.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 06a715b0dc..f502c3830a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -117,7 +117,7 @@ jobs: steps: - name: setup msys2 - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0 + uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # v2.31.0 with: cache: false msystem: ${{ matrix.msys2.msystem }} From 8dc85aebe013a9c63d2a77ca1feb0b7c50018556 Mon Sep 17 00:00:00 2001 From: Felmon Date: Thu, 26 Mar 2026 03:51:33 -0600 Subject: [PATCH 488/561] docs: document benchmark_min_time CLI forms (#2154) * docs: document benchmark_min_time CLI forms * chore: trigger CLA rescan * docs: clarify benchmark_min_time precedence --- AUTHORS | 1 + CONTRIBUTORS | 1 + docs/user_guide.md | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/AUTHORS b/AUTHORS index f3f29d6964..bea19b3056 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,6 +32,7 @@ Evgeny Safronov Fabien Pichot Federico Ficarelli Felix Homann +Felmon Fekadu Gergely Meszaros Gergő Szitár Google Inc. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a88240c60b..c3f6789aff 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -52,6 +52,7 @@ Fabien Pichot Fanbo Meng Federico Ficarelli Felix Homann +Felmon Fekadu Geoffrey Martin-Noble Gergely Meszaros Gergő Szitár diff --git a/docs/user_guide.md b/docs/user_guide.md index b2e6975361..c09d77554f 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -252,6 +252,32 @@ iterations is at least one, not more than 1e9, until CPU time is greater than the minimum time, or the wallclock time is 5x minimum time. The minimum time is set per benchmark by calling `MinTime` on the registered benchmark object. +The minimum time can also be set for all benchmarks with the +`--benchmark_min_time=` command-line option. This flag supports two +forms: + +* `--benchmark_min_time=s` sets the minimum running time for each + benchmark repetition in seconds. +* `--benchmark_min_time=x` runs each benchmark repetition for an + explicit number of iterations instead of using the dynamic time-based + iteration selection. This applies to benchmarks that do not already specify + an explicit iteration count in code. + +For compatibility, bare numeric values such as `--benchmark_min_time=0.5` are +also interpreted as seconds, but the explicit `s` suffix is preferred for +clarity. + +For example: + +```bash +$ ./run_benchmarks.x --benchmark_min_time=0.5s +$ ./run_benchmarks.x --benchmark_min_time=100x +``` + +If a benchmark specifies its own `MinTime()` or `Iterations()` in code, those +per-benchmark settings take precedence over the corresponding +`--benchmark_min_time` command-line forms. + Furthermore warming up a benchmark might be necessary in order to get stable results because of e.g caching effects of the code under benchmark. Warming up means running the benchmark a given amount of time, before From 2d13d40feac8cf93db319b3c7ad404622735e71a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 09:01:56 +0100 Subject: [PATCH 489/561] Bump astral-sh/setup-uv from 7.6.0 to 8.0.0 (#2160) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.6.0 to 8.0.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/37802adc94f370d6bfd71619e3f0bf239e1f3b78...cec208311dfd045dd5311c1add060b2062131d57) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index dae8833c1c..787003bbb2 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 7627f011c1..4db2fcf16c 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@ee02a1537ce3071a004a6b08c41e72f0fdc42d9a # v3.4.0 From e91678e30b68952c90f52b043716c9183544e463 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 09:25:01 +0100 Subject: [PATCH 490/561] Bump lukka/get-cmake from 4.3.0 to 4.3.1 (#2159) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/b78306120111dc2522750771cfd09ee7ca723687...ea83089aa35e08e459464341fe24ad024ee2466f) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 2a2ad3e58a..c8d10b4f89 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@b78306120111dc2522750771cfd09ee7ca723687 # latest + - uses: lukka/get-cmake@ea83089aa35e08e459464341fe24ad024ee2466f # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f502c3830a..362adb7305 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@b78306120111dc2522750771cfd09ee7ca723687 # latest + - uses: lukka/get-cmake@ea83089aa35e08e459464341fe24ad024ee2466f # latest - name: configure cmake run: > From 767188971dcf02b0759e029565be31f8815698fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 09:31:37 +0100 Subject: [PATCH 491/561] Bump numpy from 2.4.3 to 2.4.4 in /tools (#2158) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.3 to 2.4.4. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.3...v2.4.4) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index e46989259f..bdf86cf2c8 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.4.3 +numpy == 2.4.4 scipy == 1.17.1 From fc8a082c6046691091eecea36b2972a50c96c8f2 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:57:26 +0100 Subject: [PATCH 492/561] feat: Add ScopedPauseTiming RAII helper (#2157) * feat: Add ScopedPauseTiming RAII helper Adds a new `benchmark::ScopedPauseTiming` class that provides a convenient RAII-style mechanism for pausing and resuming benchmark timers. This is less error-prone than manually calling `PauseTiming` and `ResumeTiming`, as it guarantees that the timer is resumed when the scope is exited. - Added `ScopedPauseTiming` to `include/benchmark/state.h`. - Added a new test `test/scoped_pause_test.cc` to verify the functionality and prevent regressions. - Updated `test/CMakeLists.txt` to include the new test. - Added documentation for the new feature in `docs/user_guide.md`. * Bump astral-sh/setup-uv from 7.6.0 to 8.0.0 (#2160) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.6.0 to 8.0.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/37802adc94f370d6bfd71619e3f0bf239e1f3b78...cec208311dfd045dd5311c1add060b2062131d57) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump lukka/get-cmake from 4.3.0 to 4.3.1 (#2159) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/b78306120111dc2522750771cfd09ee7ca723687...ea83089aa35e08e459464341fe24ad024ee2466f) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> * Bump numpy from 2.4.3 to 2.4.4 in /tools (#2158) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.3 to 2.4.4. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.3...v2.4.4) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> * handle move operators * Use manual time instead of real time for better repeatability --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/user_guide.md | 23 +++++++++++++++++++++++ include/benchmark/state.h | 17 +++++++++++++++++ test/CMakeLists.txt | 3 +++ test/scoped_pause_test.cc | 30 ++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 test/scoped_pause_test.cc diff --git a/docs/user_guide.md b/docs/user_guide.md index c09d77554f..130319603d 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1066,6 +1066,29 @@ BENCHMARK(BM_SetInsert_With_Timer_Control)->Ranges({{1<<10, 8<<10}, {128, 512}}) ``` +For convenience, a `ScopedPauseTiming` class is provided to manage pausing and +resuming timers within a scope. This is less error-prone than manually calling +`PauseTiming` and `ResumeTiming`. + + +```c++ +static void BM_SetInsert_With_Scoped_Timer_Control(benchmark::State& state) { + std::set data; + for (auto _ : state) { + { + benchmark::ScopedPauseTiming pause(state); // Pauses timing + data = ConstructRandomSet(state.range(0)); + } // Timing resumes automatically when 'pause' goes out of scope + + // The rest will be measured. + for (int j = 0; j < state.range(1); ++j) + data.insert(RandomNumber()); + } +} +BENCHMARK(BM_SetInsert_With_Scoped_Timer_Control)->Ranges({{1<<10, 8<<10}, {128, 512}}); +``` + + ## Manual Timing diff --git a/include/benchmark/state.h b/include/benchmark/state.h index e9cdf0571a..356c5509a0 100644 --- a/include/benchmark/state.h +++ b/include/benchmark/state.h @@ -256,6 +256,23 @@ inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { return StateIterator(); } +class ScopedPauseTiming { + public: + explicit ScopedPauseTiming(State& state) : state_(state) { + state_.PauseTiming(); + } + ~ScopedPauseTiming() { state_.ResumeTiming(); } + + ScopedPauseTiming(const ScopedPauseTiming&) = delete; + void operator=(const ScopedPauseTiming&) = delete; + + ScopedPauseTiming(ScopedPauseTiming&&) = delete; + void operator=(ScopedPauseTiming&&) = delete; + + private: + State& state_; +}; + } // namespace benchmark #if defined(_MSC_VER) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2917efa513..374c09fa3f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -225,6 +225,9 @@ benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark compile_output_test(locale_impermeability_test) benchmark_add_test(NAME locale_impermeability_test COMMAND locale_impermeability_test) +compile_output_test(scoped_pause_test) +benchmark_add_test(NAME scoped_pause_test COMMAND scoped_pause_test) + ############################################################################### # GoogleTest Unit Tests ############################################################################### diff --git a/test/scoped_pause_test.cc b/test/scoped_pause_test.cc new file mode 100644 index 0000000000..93bcfc25a0 --- /dev/null +++ b/test/scoped_pause_test.cc @@ -0,0 +1,30 @@ + +#include +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// BM_ScopedPause sleeps for 10ms in a ScopedPauseTiming block. +// The reported time should be much less than 10ms. +void BM_ScopedPause(benchmark::State& state) { + for (auto _ : state) { + benchmark::ScopedPauseTiming pause(state); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + state.SetIterationTime(0.0); + } +} +BENCHMARK(BM_ScopedPause)->UseManualTime()->Iterations(1); + +void CheckResults(Results const& results) { + // Check that the real time is much less than the 10ms sleep time. + // Allow for up to 1ms of timing noise/overhead. + CHECK_FLOAT_RESULT_VALUE(results, "real_time", LT, 1e6, 0.0); +} +CHECK_BENCHMARK_RESULTS("BM_ScopedPause", &CheckResults); + +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); + return 0; +} From 4fa80728660aa04f4e405f047a90c8c560189782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Gr=C3=BCninger?= Date: Sun, 5 Apr 2026 20:52:15 +0200 Subject: [PATCH 493/561] Fix two GCC 16 issues (#2164) * [test] Mark unused variables Found by GCC (-Wunused-but-set-variable). * [utils] Add missing include for export macro --- include/benchmark/utils.h | 1 + test/basic_test.cc | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/benchmark/utils.h b/include/benchmark/utils.h index 2be0d3f02a..681d938a0d 100644 --- a/include/benchmark/utils.h +++ b/include/benchmark/utils.h @@ -19,6 +19,7 @@ #include #include +#include "benchmark/export.h" #include "benchmark/macros.h" namespace benchmark { diff --git a/test/basic_test.cc b/test/basic_test.cc index e1db1cb02f..a20e5b4910 100644 --- a/test/basic_test.cc +++ b/test/basic_test.cc @@ -1,4 +1,5 @@ +#include "benchmark/macros.h" #include "benchmark/registration.h" #include "benchmark/state.h" #include "benchmark/types.h" @@ -150,7 +151,7 @@ BENCHMARK(BM_RangedFor); template void BM_OneTemplateFunc(benchmark::State& state) { auto arg = state.range(0); - T sum = 0; + BENCHMARK_UNUSED T sum = 0; for (auto _ : state) { sum += static_cast(arg); } @@ -161,8 +162,8 @@ BENCHMARK(BM_OneTemplateFunc)->Arg(1); template void BM_TwoTemplateFunc(benchmark::State& state) { auto arg = state.range(0); - A sum = 0; - B prod = 1; + BENCHMARK_UNUSED A sum = 0; + BENCHMARK_UNUSED B prod = 1; for (auto _ : state) { sum += static_cast(arg); prod *= static_cast(arg); From 8abf1e701fbd88c8170f48fe0558247e2e5f8e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Gr=C3=BCninger?= Date: Sun, 5 Apr 2026 22:54:59 +0200 Subject: [PATCH 494/561] [doc] Properly document CMake minimum required version as 3.13 (#2162) --- CMakeLists.txt | 2 +- README.md | 4 +--- docs/dependencies.md | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 254fd3742c..ae02e772c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Require CMake 3.10. If available, use the policies up to CMake 3.22. +# Require CMake 3.13. If available, use the policies up to CMake 3.22. cmake_minimum_required (VERSION 3.13...3.22) project (benchmark VERSION 1.9.5 LANGUAGES CXX) diff --git a/README.md b/README.md index db99409333..ab08e1f11e 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,7 @@ $ cd benchmark # Make a build directory to place the build output. $ cmake -E make_directory "build" # Generate build system files with cmake, and download any dependencies. -$ cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release ../ -# or, starting with CMake 3.13, use a simpler form: -# cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release -S . -B "build" +$ cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release -S . -B "build" # Build the library. $ cmake --build "build" --config Release ``` diff --git a/docs/dependencies.md b/docs/dependencies.md index 98ce996391..fdb7f19b2f 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -5,7 +5,7 @@ particular the ["Build Systems" section](https://opensource.google/documentation ## CMake -The current supported version is CMake 3.10 as of 2023-08-10. Most modern +The current supported version is CMake 3.13 as of 2024-10-24. Most modern distributions include newer versions, for example: * Ubuntu 20.04 provides CMake 3.16.3 From 8586b50ae38b982ba75de9b159c391b0ba754e92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:36:19 +0100 Subject: [PATCH 495/561] Bump pypa/cibuildwheel from 3.4.0 to 3.4.1 (#2161) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.4.0 to 3.4.1. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/ee02a1537ce3071a004a6b08c41e72f0fdc42d9a...8d2b08b68458a16aeb24b64e68a09ab1c8e82084) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 3.4.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4db2fcf16c..9e0220a33a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@ee02a1537ce3071a004a6b08c41e72f0fdc42d9a # v3.4.0 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From 88a927faf93842dffcc2e2831ab264fbdb5032e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:59:42 +0100 Subject: [PATCH 496/561] Bump egor-tensin/setup-clang from 2.1 to 2.2 (#2165) Bumps [egor-tensin/setup-clang](https://github.com/egor-tensin/setup-clang) from 2.1 to 2.2. - [Release notes](https://github.com/egor-tensin/setup-clang/releases) - [Commits](https://github.com/egor-tensin/setup-clang/compare/471a6f8ef1d449dba8e1a51780e7f943572a3f99...8092a31dc33b0c41ee7cc5bb81fd0267490a0161) --- updated-dependencies: - dependency-name: egor-tensin/setup-clang dependency-version: '2.2' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sanitizer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 8024752989..0c82a2af66 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -52,7 +52,7 @@ jobs: echo "ASAN_OPTIONS=alloc_dealloc_mismatch=0" >> $GITHUB_ENV - name: setup clang - uses: egor-tensin/setup-clang@471a6f8ef1d449dba8e1a51780e7f943572a3f99 # v2.1 + uses: egor-tensin/setup-clang@8092a31dc33b0c41ee7cc5bb81fd0267490a0161 # v2.2 with: version: latest platform: x64 From 7bf975066c82bac78c887786d0003f6e50b046f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 09:22:36 +0100 Subject: [PATCH 497/561] Bump pypa/gh-action-pypi-publish from 1.13.0 to 1.14.0 (#2166) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.13.0 to 1.14.0. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e...cef221092ed1bacb1cc03d23a2d87d1d172e277b) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-version: 1.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 9e0220a33a..164be642c2 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -81,4 +81,4 @@ jobs: path: dist pattern: dist-* merge-multiple: true - - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 + - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 From 1eceef840f9230b27a668fdaadecae4b44557d9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:45:11 +0100 Subject: [PATCH 498/561] Bump actions/cache from 5.0.4 to 5.0.5 (#2169) Bumps [actions/cache](https://github.com/actions/cache) from 5.0.4 to 5.0.5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/668228422ae6a00e4ad889ee87cd7109ec5666a7...27d5ce7f107fe9357f9df03efb73ab90386fccae) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 5e5b779475..93a7e9380d 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: mount bazel cache - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 env: cache-name: bazel-cache with: From af64526cd3dea79fad9c8acb27cf85b881ef25c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 10:49:13 +0100 Subject: [PATCH 499/561] Bump astral-sh/setup-uv from 8.0.0 to 8.1.0 (#2171) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.0.0 to 8.1.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/cec208311dfd045dd5311c1add060b2062131d57...08807647e7069bb48b6ef5acd8ec9567f424441b) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 787003bbb2..547f01c7c1 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 164be642c2..0b1a2de6b7 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 From 221171c2d34a9af9c4849fe4abe260e2f0fbe82c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 11:08:41 +0100 Subject: [PATCH 500/561] Bump actions/upload-artifact from 7.0.0 to 7.0.1 (#2168) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 0b1a2de6b7..b1b3bb4d12 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -25,7 +25,7 @@ jobs: - run: python -m pip install build - name: Build sdist run: python -m build --sdist - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: dist-sdist path: dist/*.tar.gz @@ -64,7 +64,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-15-intel' && 10.14 || 11.0 }} - name: Upload Google Benchmark ${{ matrix.os }} wheels - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: dist-${{ matrix.os }} path: wheelhouse/*.whl From 96c7ddc2c1638ad2a238bf6cb3eec0eb0caa03a6 Mon Sep 17 00:00:00 2001 From: Ben Beasley Date: Mon, 20 Apr 2026 21:58:11 +0100 Subject: [PATCH 501/561] In PerfCountersTest.MultiThreaded, serialize worker threads (#2175) Fixes https://github.com/google/benchmark/issues/2173 Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- test/perf_counters_gtest.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index 6c923be897..c4f287921a 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -1,3 +1,4 @@ +#include #include #include @@ -283,7 +284,16 @@ void measure(size_t threadcount, std::map* before, BM_CHECK_NE(before, nullptr); BM_CHECK_NE(after, nullptr); std::vector threads(threadcount); - auto work = [&]() { BM_CHECK(do_work() > 1000); }; + // Because we do not care whether the threads execute concurrently, but we do + // care that they do all of their work between the SnapshotAndCombine calls, + // we serialize them with a mutex. See + // https://github.com/google/benchmark/issues/2173. + std::mutex mutex; + auto work = [&mutex]() { + mutex.lock(); + BM_CHECK(do_work() > 1000); + mutex.unlock(); + }; // We need to first set up the counters, then start the threads, so the // threads would inherit the counters. But later, we need to first destroy @@ -292,10 +302,12 @@ void measure(size_t threadcount, std::map* before, // threadpool. auto counters = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}); + mutex.lock(); for (auto& t : threads) { t = std::thread(work); } *before = SnapshotAndCombine(counters); + mutex.unlock(); for (auto& t : threads) { t.join(); } From 33e9abfce41f4d2a5d187842d7a4ce29e3f1ba94 Mon Sep 17 00:00:00 2001 From: anish <145943060+anishesg@users.noreply.github.com> Date: Thu, 23 Apr 2026 14:20:36 -0400 Subject: [PATCH 502/561] Fix thread safety attribute detection failing to link in CMake check (#2178) The `cmake/thread_safety_attributes.cpp` check was including `../src/mutex.h`, which transitively pulls in `check.h`. That header declares `benchmark::internal::GetAbortHandler()` with `BENCHMARK_EXPORT`, which requires linking against the benchmark library. Since `try_run` in `CXXFeatureCheck.cmake` only links against `BENCHMARK_CXX_LIBRARIES` (which doesn't include the full library at check time), the check failed to link, leaving `HAVE_THREAD_SAFETY_ATTRIBUTES` undefined. Signed-off-by: anish k --- cmake/thread_safety_attributes.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/cmake/thread_safety_attributes.cpp b/cmake/thread_safety_attributes.cpp index 46161babdb..1069a90a21 100644 --- a/cmake/thread_safety_attributes.cpp +++ b/cmake/thread_safety_attributes.cpp @@ -1,4 +1,25 @@ -#define HAVE_THREAD_SAFETY_ATTRIBUTES -#include "../src/mutex.h" +#if defined(__clang__) +#define THREAD_ANNOTATION_ATTRIBUTE_(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE_(x) +#endif -int main() {} +#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE_(capability(x)) +#define ACQUIRE() THREAD_ANNOTATION_ATTRIBUTE_(acquire_capability()) +#define RELEASE() THREAD_ANNOTATION_ATTRIBUTE_(release_capability()) + +class CAPABILITY("mutex") Mutex { + public: + void lock() ACQUIRE(); + void unlock() RELEASE(); +}; + +void Mutex::lock() ACQUIRE() {} +void Mutex::unlock() RELEASE() {} + +int main() { + Mutex m; + m.lock(); + m.unlock(); + return 0; +} From b8081188293948a64560a557c9dcd96a78a96420 Mon Sep 17 00:00:00 2001 From: qorex#dev Date: Fri, 24 Apr 2026 19:09:22 +0500 Subject: [PATCH 503/561] Replace deprecated _ReadWriteBarrier with std::atomic_signal_fence in MSVC path (#2177) * Replace deprecated _ReadWriteBarrier with std::atomic_signal_fence * use ClobberMemory() instead of inlining atomic_signal_fence * add qorexdev to AUTHORS and CONTRIBUTORS --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- AUTHORS | 1 + CONTRIBUTORS | 1 + include/benchmark/utils.h | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index bea19b3056..00ac593e19 100644 --- a/AUTHORS +++ b/AUTHORS @@ -61,6 +61,7 @@ Olga Fadeeva Ori Livneh Paul Redmond Prithvi Rao +qorexdev Radoslav Yovchev Raghu Raja Rainer Orth diff --git a/CONTRIBUTORS b/CONTRIBUTORS index c3f6789aff..4016558f51 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -85,6 +85,7 @@ Pascal Leroy Paul Redmond Pierre Phaneuf Prithvi Rao +qorexdev Radoslav Yovchev Raghu Raja Rainer Orth diff --git a/include/benchmark/utils.h b/include/benchmark/utils.h index 681d938a0d..0e4d95dc43 100644 --- a/include/benchmark/utils.h +++ b/include/benchmark/utils.h @@ -127,19 +127,19 @@ BENCHMARK_DEPRECATED_MSG( "undesired compiler optimizations in benchmarks") inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { internal::UseCharPointer(&reinterpret_cast(value)); - _ReadWriteBarrier(); + ClobberMemory(); } template inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { internal::UseCharPointer(&reinterpret_cast(value)); - _ReadWriteBarrier(); + ClobberMemory(); } template inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { internal::UseCharPointer(&reinterpret_cast(value)); - _ReadWriteBarrier(); + ClobberMemory(); } #else template From ec0ce391ce37128b876a01166042c575f38ac328 Mon Sep 17 00:00:00 2001 From: Shreejay Kurhade <93570022+shreejaykurhade@users.noreply.github.com> Date: Sun, 26 Apr 2026 22:37:35 +0530 Subject: [PATCH 504/561] Document naming benchmark arguments (#2180) --- docs/user_guide.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/user_guide.md b/docs/user_guide.md index 130319603d..ffe2567aa5 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -486,6 +486,36 @@ static void CustomArguments(benchmark::Benchmark* b) { BENCHMARK(BM_SetInsert)->Apply(CustomArguments); ``` +### Naming Benchmark Arguments + +When a benchmark takes one or more numeric arguments, the generated benchmark +names can be made easier to read by naming those arguments. Use `ArgName` for a +single argument and `ArgNames` for multiple arguments. + +```c++ +BENCHMARK(BM_memcpy)->Range(8, 512)->ArgName("bytes"); +``` + +This changes names such as `BM_memcpy/8` and `BM_memcpy/512` to +`BM_memcpy/bytes:8` and `BM_memcpy/bytes:512`. + +For benchmarks with more than one argument, each name labels the corresponding +argument position. + + +```c++ +BENCHMARK(BM_SetInsert) + ->Args({100, 128}) + ->Args({200, 512}) + ->ArgNames({"size", "inserts"}); +``` + + +This produces names such as `BM_SetInsert/size:100/inserts:128` and +`BM_SetInsert/size:200/inserts:512`. Empty argument names are allowed and leave +that argument value unlabeled, for example `ArgNames({"size", ""})` produces +names like `BM_SetInsert/size:100/128`. + ### Passing Arbitrary Arguments to a Benchmark It is possible to define a benchmark that takes an arbitrary number From f43ed80fa2b6ca9411081892bf961513f56489df Mon Sep 17 00:00:00 2001 From: Shreejay Kurhade <93570022+shreejaykurhade@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:59:29 +0530 Subject: [PATCH 505/561] Docs: JSON output format (#2181) * Document JSON output format * Soften JSON output documentation * Clarify JSON counter output example --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- docs/user_guide.md | 53 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index ffe2567aa5..4ac63a4cf0 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -87,43 +87,84 @@ BM_SetInsert/1024/8 32065 32913 21375 949.487k BM_SetInsert/1024/10 33157 33648 21431 1.13369MiB/s 290.225k items/s ``` -The JSON format outputs human readable json split into two top level attributes. -The `context` attribute contains information about the run in general, including -information about the CPU and the date. -The `benchmarks` attribute contains a list of every benchmark run. Example json -output looks like: +The JSON format outputs human readable JSON split into two top level +attributes: `context` and `benchmarks`. This format is useful for tools that +need to consume benchmark results without parsing console output. + +The `context` object contains information about the run in general, including +the date, host, CPU, caches, load average, benchmark library version, and +`json_schema_version`. Extra context added with `benchmark::AddCustomContext` or +`--benchmark_context` is emitted as additional string fields in `context`. + +The `benchmarks` array contains an object for each benchmark result. Iteration +results commonly include fields such as `name`, `run_name`, `run_type`, +`iterations`, `real_time`, `cpu_time`, `time_unit`, and `threads`. Depending on +benchmark configuration, result objects can also include aggregate fields, +asymptotic complexity fields, skip/error fields, memory metrics, labels, user +counters, and user-requested performance counters. + +User counters, including rates such as `bytes_per_second` and +`items_per_second`, are emitted as additional numeric fields on the benchmark +object. User-requested performance counters are reported the same way. + +The JSON output may gain new fields over time. Consumers should ignore unknown +fields and tolerate optional fields being absent. This allows the format to be +extended while preserving compatibility for existing consumers. + +An abbreviated example JSON output looks like: ```json { "context": { "date": "2015/03/17-18:40:25", + "host_name": "my-host", "num_cpus": 40, "mhz_per_cpu": 2801, "cpu_scaling_enabled": false, - "build_type": "debug" + "caches": [ + { + "type": "Data", + "level": 1, + "size": 32768, + "num_sharing": 2 + } + ], + "load_avg": [], + "library_version": "vX.Y.Z", + "library_build_type": "debug", + "json_schema_version": 1 }, "benchmarks": [ { "name": "BM_SetInsert/1024/1", + "run_name": "BM_SetInsert/1024/1", + "run_type": "iteration", "iterations": 94877, "real_time": 29275, "cpu_time": 29836, + "time_unit": "ns", "bytes_per_second": 134066, "items_per_second": 33516 }, { "name": "BM_SetInsert/1024/8", + "run_name": "BM_SetInsert/1024/8", + "run_type": "iteration", "iterations": 21609, "real_time": 32317, "cpu_time": 32429, + "time_unit": "ns", "bytes_per_second": 986770, "items_per_second": 246693 }, { "name": "BM_SetInsert/1024/10", + "run_name": "BM_SetInsert/1024/10", + "run_type": "iteration", "iterations": 21393, "real_time": 32724, "cpu_time": 33355, + "time_unit": "ns", "bytes_per_second": 1199226, "items_per_second": 299807 } From ff773f8c97717424a7855ce0933b036b79628a02 Mon Sep 17 00:00:00 2001 From: Eddie Nolan Date: Mon, 27 Apr 2026 20:21:39 -0400 Subject: [PATCH 506/561] BENCHMARK_ENABLE_WERROR=Off should also disable -pedantic-errors (#2183) Otherwise Clang 22 builds fail with: ``` /build/_deps/benchmark-src/include/benchmark/benchmark.h:1442:30: error: '__COUNTER__' is a C2y extension [-Werror,-Wc2y-extensions] 1442 | #if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) | ^ ``` --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae02e772c7..d27698adc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,13 +205,13 @@ else() add_cxx_compiler_flag(-Wformat=2) if(BENCHMARK_ENABLE_WERROR) add_cxx_compiler_flag(-Werror) + add_cxx_compiler_flag(-pedantic-errors) endif() if (NOT BENCHMARK_ENABLE_TESTING) # Disable warning when compiling tests as gtest does not use 'override'. add_cxx_compiler_flag(-Wsuggest-override) endif() add_cxx_compiler_flag(-pedantic) - add_cxx_compiler_flag(-pedantic-errors) add_cxx_compiler_flag(-Wshorten-64-to-32) add_cxx_compiler_flag(-fstrict-aliasing) # Disable warnings regarding deprecated parts of the library while building From dea73efb31bced28ff9a9dbbac8165987bf92c66 Mon Sep 17 00:00:00 2001 From: Mister Lobster Date: Thu, 7 May 2026 06:12:09 -0400 Subject: [PATCH 507/561] docs: Add comprehensive command-line options documentation (#2187) This commit adds detailed documentation for all benchmark command-line options to the user guide. Each option is documented with: - Description of what the option does - Default value (where applicable) - Valid values (where applicable) - Example usage The documentation is organized into logical categories: - Benchmark Selection and Execution - Timing and Repetition Control - Output Formatting - Reporting Options - Performance Counters and Context - Miscellaneous This addresses issue #2156 where users requested public documentation of command-line options instead of having to run --help. Closes #2156 --- docs/user_guide.md | 205 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/docs/user_guide.md b/docs/user_guide.md index 4ac63a4cf0..14e20047ca 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -2,6 +2,8 @@ ## Command Line +[Command Line Options](#command-line-options) + [Output Formats](#output-formats) [Output Files](#output-files) @@ -65,6 +67,209 @@ [Disabling CPU Frequency Scaling](#disabling-cpu-frequency-scaling) [Reducing Variance in Benchmarks](reducing_variance.md) + + +## Command Line Options + +Benchmarks accept options that may be specified either through their command line interface or by setting environment variables before execution. For every `--option_flag=` CLI switch, a corresponding environment variable `OPTION_FLAG=` exists and is used as default if set (CLI switches always prevail). + +### Benchmark Selection and Execution + +#### `--benchmark_list_tests` (BENCHMARK_LIST_TESTS) + +Print a list of all benchmark names and exit. This option overrides all other options. + +**Example:** +```bash +$ ./benchmark --benchmark_list_tests +BM_SomeFunction +BM_AnotherFunction +``` + +#### `--benchmark_filter=` (BENCHMARK_FILTER) + +A regular expression that specifies the set of benchmarks to execute. If this flag is empty, or if this flag is the string "all", all benchmarks linked into the binary are run. + +**Example:** +```bash +$ ./benchmark --benchmark_filter=BM_memcpy/32 +``` + +#### `--benchmark_dry_run` (BENCHMARK_DRY_RUN) + +If enabled, forces each benchmark to execute exactly one iteration and one repetition, bypassing any configured `MinTime()`, `MinWarmUpTime()`, `Iterations()`, or `Repetitions()`. This is useful for quickly verifying that benchmarks can run successfully without waiting for full execution. + +**Example:** +```bash +$ ./benchmark --benchmark_dry_run +``` + +#### `--benchmark_enable_random_interleaving` (BENCHMARK_ENABLE_RANDOM_INTERLEAVING) + +If set, enable random interleaving of repetitions of all benchmarks. This can help reduce the impact of system state changes on benchmark results. See [GitHub issue #1051](https://github.com/google/benchmark/issues/1051) for details. + +**Example:** +```bash +$ ./benchmark --benchmark_enable_random_interleaving +``` + +### Timing and Repetition Control + +#### `--benchmark_min_time=` (BENCHMARK_MIN_TIME) + +Specifies the minimum amount of time (in seconds) that each benchmark should run. For CPU-time based tests, this is the lower bound on the total CPU time used by all threads that make up the test. For real-time based tests, this is the lower bound on the elapsed time of the benchmark execution, regardless of number of threads. + +**Default:** `0.5` seconds + +**Example:** +```bash +$ ./benchmark --benchmark_min_time=1.0 +``` + +#### `--benchmark_min_warmup_time=` (BENCHMARK_MIN_WARMUP_TIME) + +Minimum number of seconds a benchmark should be run before results should be taken into account. This can be necessary for benchmarks of code which needs to fill some form of cache before performance is of interest. Results gathered within this period are discarded and not used for the reported result. + +**Default:** `0.0` seconds + +**Example:** +```bash +$ ./benchmark --benchmark_min_warmup_time=0.5 +``` + +#### `--benchmark_repetitions=` (BENCHMARK_REPETITIONS) + +The number of runs of each benchmark. If greater than 1, the mean and standard deviation of the runs will be reported. + +**Default:** `1` + +**Example:** +```bash +$ ./benchmark --benchmark_repetitions=5 +``` + +### Output Formatting + +#### `--benchmark_format=` (BENCHMARK_FORMAT) + +The format to use for console output. Valid values are 'console', 'json', or 'csv'. See [Output Formats](#output-formats) for more details. + +**Default:** `console` + +**Example:** +```bash +$ ./benchmark --benchmark_format=json +``` + +#### `--benchmark_out=` (BENCHMARK_OUT) + +The file to write additional output to. The output format is controlled by `--benchmark_out_format`. Specifying this option does not suppress console output. + +**Example:** +```bash +$ ./benchmark --benchmark_out=results.json +``` + +#### `--benchmark_out_format=` (BENCHMARK_OUT_FORMAT) + +The format to use for file output specified by `--benchmark_out`. Valid values are 'console', 'json', or 'csv'. + +**Default:** `json` + +**Example:** +```bash +$ ./benchmark --benchmark_out=results.csv --benchmark_out_format=csv +``` + +#### `--benchmark_color=` (BENCHMARK_COLOR) + +Whether to use colors in the output. Valid values are 'true'/'yes'/1, 'false'/'no'/0, and 'auto'. 'auto' means to use colors if the output is being sent to a terminal and the TERM environment variable is set to a terminal type that supports colors. + +**Default:** `auto` + +**Example:** +```bash +$ ./benchmark --benchmark_color=false +``` + +#### `--benchmark_time_unit=` (BENCHMARK_TIME_UNIT) + +Set the default time unit to use for reports. Valid values are 'ns' (nanoseconds), 'us' (microseconds), 'ms' (milliseconds), or 's' (seconds). + +**Default:** (empty, uses automatic selection) + +**Example:** +```bash +$ ./benchmark --benchmark_time_unit=us +``` + +### Reporting Options + +#### `--benchmark_report_aggregates_only` (BENCHMARK_REPORT_AGGREGATES_ONLY) + +When enabled, only the mean, standard deviation, and other statistics are reported for repeated benchmarks. This affects all reporters (both console and file output). + +**Default:** `false` + +**Example:** +```bash +$ ./benchmark --benchmark_repetitions=5 --benchmark_report_aggregates_only +``` + +#### `--benchmark_display_aggregates_only` (BENCHMARK_DISPLAY_AGGREGATES_ONLY) + +When enabled, only the mean, standard deviation, and other statistics are displayed for repeated benchmarks. Unlike `--benchmark_report_aggregates_only`, this only affects the display (console) reporter, not the file reporter, which will still contain all output. + +**Default:** `false` + +**Example:** +```bash +$ ./benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only +``` + +#### `--benchmark_counters_tabular` (BENCHMARK_COUNTERS_TABULAR) + +Whether to use tabular format when printing user counters to the console. Valid values: 'true'/'yes'/1, 'false'/'no'/0. + +**Default:** `false` + +**Example:** +```bash +$ ./benchmark --benchmark_counters_tabular=true +``` + +### Performance Counters and Context + +#### `--benchmark_perf_counters=` (BENCHMARK_PERF_COUNTERS) + +List of additional performance counters to collect, in libpfm format. For more information about libpfm, see the [libpfm documentation](https://man7.org/linux/man-pages/man3/libpfm.3.html). + +**Example:** +```bash +$ ./benchmark --benchmark_perf_counters=cycles,instructions,cache-misses +``` + +#### `--benchmark_context=` (BENCHMARK_CONTEXT) + +Extra context to include in the output, formatted as comma-separated key-value pairs. This context is included in the JSON output's `context` object. + +**Example:** +```bash +$ ./benchmark --benchmark_context=compiler=clang,version=13 +``` + +### Miscellaneous + +#### `-v` (V) + +The level of verbose logging to output. Higher values produce more verbose output. + +**Default:** `0` + +**Example:** +```bash +$ ./benchmark -v +``` From 935a2f53171dcf767cd4f20794ece6362e75723f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 21:21:50 +0100 Subject: [PATCH 508/561] Bump egor-tensin/setup-clang from 2.2 to 2.3 (#2188) Bumps [egor-tensin/setup-clang](https://github.com/egor-tensin/setup-clang) from 2.2 to 2.3. - [Release notes](https://github.com/egor-tensin/setup-clang/releases) - [Commits](https://github.com/egor-tensin/setup-clang/compare/8092a31dc33b0c41ee7cc5bb81fd0267490a0161...23bc15cd4207e45f1566447deb48f4ff3ef932cb) --- updated-dependencies: - dependency-name: egor-tensin/setup-clang dependency-version: '2.3' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sanitizer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 0c82a2af66..f54ef34f4f 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -52,7 +52,7 @@ jobs: echo "ASAN_OPTIONS=alloc_dealloc_mismatch=0" >> $GITHUB_ENV - name: setup clang - uses: egor-tensin/setup-clang@8092a31dc33b0c41ee7cc5bb81fd0267490a0161 # v2.2 + uses: egor-tensin/setup-clang@23bc15cd4207e45f1566447deb48f4ff3ef932cb # v2.3 with: version: latest platform: x64 From c47bbfbdbbf59d6fbd2df110965374ef3bfe9bd7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 22:01:20 +0100 Subject: [PATCH 509/561] Bump lukka/get-cmake from 4.3.1 to 4.3.2 (#2176) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.3.1 to 4.3.2. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/ea83089aa35e08e459464341fe24ad024ee2466f...7bfc9baacbbdcb5e37957ad05c3546b3e222be3c) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.3.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index c8d10b4f89..87e4fe92e0 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@ea83089aa35e08e459464341fe24ad024ee2466f # latest + - uses: lukka/get-cmake@7bfc9baacbbdcb5e37957ad05c3546b3e222be3c # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 362adb7305..d1dfcd933f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@ea83089aa35e08e459464341fe24ad024ee2466f # latest + - uses: lukka/get-cmake@7bfc9baacbbdcb5e37957ad05c3546b3e222be3c # latest - name: configure cmake run: > From ac68e7d7de60fb55ccad12536d485d4880502cfe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 09:06:50 +0100 Subject: [PATCH 510/561] Bump numpy from 2.4.4 to 2.4.6 in /tools (#2189) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.4 to 2.4.6. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.4...v2.4.6) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index bdf86cf2c8..8232756dd6 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.4.4 +numpy == 2.4.6 scipy == 1.17.1 From 486f6ea9fb97b35c9b86b90d8b452d8d0c12b8c3 Mon Sep 17 00:00:00 2001 From: Shaway <39594020+ShawayL@users.noreply.github.com> Date: Tue, 19 May 2026 19:01:50 +0800 Subject: [PATCH 511/561] Fix .gitignore: unignore .cmake files recursively under cmake/ (#2191) --- .gitignore | 2 +- AUTHORS | 1 + CONTRIBUTORS | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8f6ce84efe..bc0c14acd7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ *.exe *.dylib *.cmake -!/cmake/*.cmake +!/cmake/**/*.cmake !/test/AssemblyTests.cmake *~ *.swp diff --git a/AUTHORS b/AUTHORS index 00ac593e19..203961b0ec 100644 --- a/AUTHORS +++ b/AUTHORS @@ -77,3 +77,4 @@ Tobias Schmidt Yixuan Qiu Yusuke Suzuki Zbigniew Skowron +XiaoWei Lu diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4016558f51..f0a4aa875d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -104,3 +104,4 @@ Tom Madams Yixuan Qiu Yusuke Suzuki Zbigniew Skowron +XiaoWei Lu From 83c826c8d9499bb3ecd02f6f4abbac1e990297fe Mon Sep 17 00:00:00 2001 From: Shaway <39594020+ShawayL@users.noreply.github.com> Date: Wed, 20 May 2026 16:55:41 +0800 Subject: [PATCH 512/561] Sort AUTHORS and CONTRIBUTORS entries (#2192) --- AUTHORS | 2 +- CONTRIBUTORS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 203961b0ec..30a041adf5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -74,7 +74,7 @@ Staffan Tjernstrom Steinar H. Gunderson Stripe, Inc. Tobias Schmidt +XiaoWei Lu Yixuan Qiu Yusuke Suzuki Zbigniew Skowron -XiaoWei Lu diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f0a4aa875d..eabd85f79e 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -101,7 +101,7 @@ Steven Wan Tobias Schmidt Tobias Ulvgård Tom Madams +XiaoWei Lu Yixuan Qiu Yusuke Suzuki Zbigniew Skowron -XiaoWei Lu From 266b9b6797d25ed97f957c14ea960bf641b3ff94 Mon Sep 17 00:00:00 2001 From: Kiwi Date: Fri, 22 May 2026 16:10:42 -0400 Subject: [PATCH 513/561] Add libpfm to pkg-config Libs.private when libpfm is enabled (#2194) The private link library derivation skips CMake targets, so the PFM::libpfm imported target was never translated into linker flags. Static consumers using pkg-config then fail to resolve pfm_* symbols. Resolve imported targets through their IMPORTED_LOCATION and emit the corresponding -L/-l flags alongside the other private libraries. --- src/CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4696594a24..0e81cdb495 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -113,6 +113,18 @@ if(NOT BUILD_SHARED_LIBS) foreach(LIB IN LISTS LINK_LIBS) if(NOT TARGET "${LIB}" AND LIB MATCHES "^[a-zA-Z0-9_.-]+$") list(APPEND BENCHMARK_PRIVATE_LINK_LIBRARIES "-l${LIB}") + elseif(TARGET "${LIB}") + get_target_property(_target_type "${LIB}" TYPE) + if(_target_type MATCHES "^(UNKNOWN|STATIC|SHARED|MODULE)_LIBRARY$") + get_target_property(_imported_loc "${LIB}" IMPORTED_LOCATION) + if(_imported_loc) + get_filename_component(_imported_dir "${_imported_loc}" DIRECTORY) + get_filename_component(_imported_name "${_imported_loc}" NAME) + string(REGEX REPLACE "^lib" "" _imported_name "${_imported_name}") + string(REGEX REPLACE "\\.(so|a|dylib)([0-9.]*)$" "" _imported_name "${_imported_name}") + list(APPEND BENCHMARK_PRIVATE_LINK_LIBRARIES "-L${_imported_dir}" "-l${_imported_name}") + endif() + endif() endif() endforeach() string(JOIN " " BENCHMARK_PRIVATE_LINK_LIBRARIES ${BENCHMARK_PRIVATE_LINK_LIBRARIES}) From 926a850aa4d4fff675f18c1b1e8fe29b40826b48 Mon Sep 17 00:00:00 2001 From: Haihan Jiang Date: Mon, 25 May 2026 13:36:50 -0700 Subject: [PATCH 514/561] Fix pkg-config paths for absolute install dirs (#2198) The general practice for `.pc` is to avoid absolute paths and use `${prefix}` variables whenever possible. --- AUTHORS | 1 + CONTRIBUTORS | 1 + cmake/benchmark.pc.in | 4 ++-- cmake/benchmark_main.pc.in | 4 +++- src/CMakeLists.txt | 14 ++++++++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 30a041adf5..082422cb81 100644 --- a/AUTHORS +++ b/AUTHORS @@ -36,6 +36,7 @@ Felmon Fekadu Gergely Meszaros Gergő Szitár Google Inc. +Haihan Jiang Henrique Bucher International Business Machines Corporation Ismael Jimenez Martinez diff --git a/CONTRIBUTORS b/CONTRIBUTORS index eabd85f79e..f22a988784 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -56,6 +56,7 @@ Felmon Fekadu Geoffrey Martin-Noble Gergely Meszaros Gergő Szitár +Haihan Jiang Hannes Hauswedell Henrique Bucher Ismael Jimenez Martinez diff --git a/cmake/benchmark.pc.in b/cmake/benchmark.pc.in index bbed29d1eb..520d14971f 100644 --- a/cmake/benchmark.pc.in +++ b/cmake/benchmark.pc.in @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} -libdir=@CMAKE_INSTALL_FULL_LIBDIR@ -includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ +libdir=@BENCHMARK_PKG_CONFIG_LIBDIR@ +includedir=@BENCHMARK_PKG_CONFIG_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: Google microbenchmark framework diff --git a/cmake/benchmark_main.pc.in b/cmake/benchmark_main.pc.in index e9d81a05ee..249de6cf98 100644 --- a/cmake/benchmark_main.pc.in +++ b/cmake/benchmark_main.pc.in @@ -1,4 +1,6 @@ -libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@BENCHMARK_PKG_CONFIG_LIBDIR@ Name: @PROJECT_NAME@ Description: Google microbenchmark framework (with main() function) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e81cdb495..59d3aeac0f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -131,7 +131,21 @@ if(NOT BUILD_SHARED_LIBS) endif() endif() +function(_cmake_path output_var install_dir path_prefix) + if(IS_ABSOLUTE "${install_dir}") + set("${output_var}" "${install_dir}" PARENT_SCOPE) + else() + # FIXME: Use cmake_path(APPEND) once the minimum CMake version is 3.20. + set("${output_var}" "\${${path_prefix}}/${install_dir}" PARENT_SCOPE) + endif() +endfunction() + +_cmake_path(BENCHMARK_PKG_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}" "exec_prefix") + +_cmake_path(BENCHMARK_PKG_CONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}" "prefix") + configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY) + configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark_main.pc.in" "${pkg_config_main}" @ONLY) export ( From c6b37eeccd91b9ca413593dabfc06b9430eb9200 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 26 May 2026 11:30:04 +0300 Subject: [PATCH 515/561] Add AGENTS.md (#2202) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- AGENTS.md | 20 ++++++++++++++++++++ CONTRIBUTING.md | 5 +++++ 2 files changed, 25 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..94e51e960d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# AI usage + +1. It is acceptable to use AI when producing contributions. +2. Any and all AI usage must be fully and explictly disclosed + in the PR description and commit message. +3. The modern (as of 2026-06) AI is a misnomer, + it is not intelligent, + it is not sentient, + it does not think, + it does not understand the code, + it is merely a next-token guesser, + therefore it is merely an (hyper-) advanced IDE. +4. Therefore, the actual person contributing + solely bears the whole responsibility for the diff, + they must understand the problem, and the solution, + and be able to constructively argue about it. + "well, AI said so, therefore it is" is not an acceptable approach. +5. All contributions shall be done by sentient beings, + fully autonomous contributions by bots, unless explicitly allowed, + is prohibited. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 43de4c9d47..eb73131f42 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,11 @@ of your first [pull request][]. 1. Finally, push the commits to your fork and submit a [pull request][]. + +## AI usage ## + +Please consult [AGENTS.md][] file. + [forking]: https://help.github.com/articles/fork-a-repo [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html [pull request]: https://help.github.com/articles/creating-a-pull-request From 6f674db907ca92b5117aacbe467c1bbba4758d0a Mon Sep 17 00:00:00 2001 From: Haihan Jiang Date: Tue, 26 May 2026 01:41:48 -0700 Subject: [PATCH 516/561] Clarify benchmark_main CMake target usage (#2205) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab08e1f11e..69b7c7db85 100644 --- a/README.md +++ b/README.md @@ -202,8 +202,11 @@ flag for option information or see the [User Guide](docs/user_guide.md). ### Usage with CMake If using CMake, it is recommended to link against the project-provided -`benchmark::benchmark` and `benchmark::benchmark_main` targets using -`target_link_libraries`. +`benchmark::benchmark` or `benchmark::benchmark_main` targets using +`target_link_libraries`. Link to `benchmark::benchmark` when your target +defines its own `main` function, or link to `benchmark::benchmark_main` to use +the default benchmark entry point. The `benchmark::benchmark_main` target links +`benchmark::benchmark` transitively. It is possible to use ```find_package``` to import an installed version of the library. ```cmake @@ -217,4 +220,6 @@ add_subdirectory(benchmark) Either way, link to the library as follows. ```cmake target_link_libraries(MyTarget benchmark::benchmark) +# Or, when you do not define your own main: +target_link_libraries(MyTarget benchmark::benchmark_main) ``` From 161bbc6af11e046a131bf86b4518a67844f30762 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 09:56:14 +0100 Subject: [PATCH 517/561] Bump lukka/get-cmake from 4.3.2 to 4.3.3 (#2196) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.3.2 to 4.3.3. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/7bfc9baacbbdcb5e37957ad05c3546b3e222be3c...591817e96fcad43505fb4eae36172462abb3a42e) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.3.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 87e4fe92e0..331022736d 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@7bfc9baacbbdcb5e37957ad05c3546b3e222be3c # latest + - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d1dfcd933f..50a8db79c6 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: lukka/get-cmake@7bfc9baacbbdcb5e37957ad05c3546b3e222be3c # latest + - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest - name: configure cmake run: > From 7417cb66455075ce85370f9c2588a3377c1417aa Mon Sep 17 00:00:00 2001 From: Haihan Jiang Date: Tue, 26 May 2026 01:57:28 -0700 Subject: [PATCH 518/561] Document static library benchmark registration (#2200) * Document static library benchmark registration * Clarify object library benchmark docs * Clarify static library benchmark docs * Address static library README wording --------- Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 69b7c7db85..e871a83d58 100644 --- a/README.md +++ b/README.md @@ -223,3 +223,18 @@ target_link_libraries(MyTarget benchmark::benchmark) # Or, when you do not define your own main: target_link_libraries(MyTarget benchmark::benchmark_main) ``` + +When benchmark sources are shared through an intermediate CMake target, choose +an object library instead of a static library: + +```cmake +add_library(shared_benchmarks OBJECT bench.cc) +target_link_libraries(shared_benchmarks benchmark::benchmark_main) +add_executable(runnable_benchmarks) +target_link_libraries(runnable_benchmarks shared_benchmarks) +``` + +This links the object file that contains `BENCHMARK` registrations into the +final executable. If those registrations are placed only in an intermediate +`STATIC` library, the linker may not copy static registration symbols, and thus +benchmarks will not be part of the final executable. From 223269f94bc162c444973977b848df20b57e68c4 Mon Sep 17 00:00:00 2001 From: Haihan Jiang Date: Tue, 26 May 2026 02:03:02 -0700 Subject: [PATCH 519/561] Document CMake embedding guidance (#2203) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- README.md | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e871a83d58..b60e2d8556 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,6 @@ target_link_libraries(MyTarget benchmark::benchmark) # Or, when you do not define your own main: target_link_libraries(MyTarget benchmark::benchmark_main) ``` - When benchmark sources are shared through an intermediate CMake target, choose an object library instead of a static library: @@ -238,3 +237,39 @@ This links the object file that contains `BENCHMARK` registrations into the final executable. If those registrations are placed only in an intermediate `STATIC` library, the linker may not copy static registration symbols, and thus benchmarks will not be part of the final executable. + +#### Embedding Google Benchmark in another CMake project + +There are two common ways to consume Google Benchmark from a CMake project: + +* Use an installed or package-managed copy, for example from a system package + manager or vcpkg, and import it with `find_package(benchmark REQUIRED)`. +* Add this repository to the source tree, for example as a submodule or + `FetchContent` dependency, and call `add_subdirectory`. + +The installed form keeps Google Benchmark's build separate from the parent +project and is usually the simplest choice for system packages and vcpkg. The +source-tree form is useful when the parent project wants to pin a specific +commit or build Google Benchmark as part of its normal CMake configure step. + +When embedding from source, most projects should turn off Google Benchmark's +tests and install rules: + +```cmake +set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "" FORCE) +set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) +set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) +add_subdirectory(third_party/benchmark) +target_link_libraries(MyTarget benchmark::benchmark) +``` + +If Google Test is not already provided by the parent build, either check out the +Google Test sources under `benchmark/googletest` or configure with +`BENCHMARK_DOWNLOAD_DEPENDENCIES=ON`. For projects that only link the benchmark +library and do not build Google Benchmark's tests, disabling +`BENCHMARK_ENABLE_GTEST_TESTS` avoids the Google Test dependency. + +Google Benchmark follows CMake's `BUILD_SHARED_LIBS` setting when selecting +static or shared library output. On Windows, keep this setting consistent with +the rest of the project and make sure the same runtime library configuration is +used across the benchmark library and the targets that link it. From d6303b29ba764c668e845dba20c4e50e21e5c8bd Mon Sep 17 00:00:00 2001 From: Haihan Jiang Date: Tue, 26 May 2026 11:39:48 -0700 Subject: [PATCH 520/561] Skip errored runs when computing repetition statistics (#2199) --- src/statistics.cc | 56 ++++++++++++++++++++++++---------------- test/repetitions_test.cc | 37 ++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/statistics.cc b/src/statistics.cc index 2c6c8584ab..619bb66746 100644 --- a/src/statistics.cc +++ b/src/statistics.cc @@ -112,10 +112,15 @@ std::vector ComputeStats( typedef BenchmarkReporter::Run Run; std::vector results; - auto error_count = std::count_if(reports.begin(), reports.end(), - [](Run const& run) { return run.skipped; }); + const auto is_successful = [](Run const& run) { + return run.skipped == internal::NotSkipped; + }; + auto successful_run = + std::find_if(reports.begin(), reports.end(), is_successful); + const auto successful_count = static_cast( + std::count_if(reports.begin(), reports.end(), is_successful)); - if (reports.size() - static_cast(error_count) < 2) { + if (successful_count < 2) { // We don't report aggregated data if there was a single run. return results; } @@ -124,12 +129,12 @@ std::vector ComputeStats( std::vector real_accumulated_time_stat; std::vector cpu_accumulated_time_stat; - real_accumulated_time_stat.reserve(reports.size()); - cpu_accumulated_time_stat.reserve(reports.size()); + real_accumulated_time_stat.reserve(successful_count); + cpu_accumulated_time_stat.reserve(successful_count); // All repetitions should be run with the same number of iterations so we // can take this information from the first benchmark. - const IterationCount run_iterations = reports.front().iterations; + const IterationCount run_iterations = successful_run->iterations; // create stats for user counters struct CounterStat { Counter c; @@ -137,6 +142,9 @@ std::vector ComputeStats( }; std::map counter_stats; for (Run const& r : reports) { + if (!is_successful(r)) { + continue; + } for (auto const& cnt : r.counters) { auto it = counter_stats.find(cnt.first); if (it == counter_stats.end()) { @@ -144,7 +152,7 @@ std::vector ComputeStats( .emplace(cnt.first, CounterStat{cnt.second, std::vector{}}) .first; - it->second.s.reserve(reports.size()); + it->second.s.reserve(successful_count); } else { BM_CHECK_EQ(it->second.c.flags, cnt.second.flags); } @@ -153,11 +161,11 @@ std::vector ComputeStats( // Populate the accumulators. for (Run const& run : reports) { - BM_CHECK_EQ(reports[0].benchmark_name(), run.benchmark_name()); - BM_CHECK_EQ(run_iterations, run.iterations); - if (run.skipped != 0u) { + BM_CHECK_EQ(successful_run->benchmark_name(), run.benchmark_name()); + if (!is_successful(run)) { continue; } + BM_CHECK_EQ(run_iterations, run.iterations); real_accumulated_time_stat.emplace_back(run.real_accumulated_time); cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time); // user counters @@ -169,26 +177,30 @@ std::vector ComputeStats( } // Only add label if it is same for all runs - std::string report_label = reports[0].report_label; - for (std::size_t i = 1; i < reports.size(); i++) { - if (reports[i].report_label != report_label) { + std::string report_label = successful_run->report_label; + for (const Run& run : reports) { + if (!is_successful(run)) { + continue; + } + if (run.report_label != report_label) { report_label = ""; break; } } const double iteration_rescale_factor = - static_cast(reports.size()) / static_cast(run_iterations); + static_cast(successful_count) / + static_cast(run_iterations); - for (const auto& Stat : *reports[0].statistics) { + for (const auto& Stat : *successful_run->statistics) { // Get the data from the accumulator to BenchmarkReporter::Run's. Run data; - data.run_name = reports[0].run_name; - data.family_index = reports[0].family_index; - data.per_family_instance_index = reports[0].per_family_instance_index; + data.run_name = successful_run->run_name; + data.family_index = successful_run->family_index; + data.per_family_instance_index = successful_run->per_family_instance_index; data.run_type = BenchmarkReporter::Run::RT_Aggregate; - data.threads = reports[0].threads; - data.repetitions = reports[0].repetitions; + data.threads = successful_run->threads; + data.repetitions = successful_run->repetitions; data.repetition_index = Run::no_repetition_index; data.aggregate_name = Stat.name_; data.aggregate_unit = Stat.unit_; @@ -199,7 +211,7 @@ std::vector ComputeStats( // Similarly, if there are N repetitions with 1 iterations each, // an aggregate will be computed over N measurements, not 1. // Thus it is best to simply use the count of separate reports. - data.iterations = static_cast(reports.size()); + data.iterations = static_cast(successful_count); data.real_accumulated_time = Stat.compute_(real_accumulated_time_stat); data.cpu_accumulated_time = Stat.compute_(cpu_accumulated_time_stat); @@ -214,7 +226,7 @@ std::vector ComputeStats( data.cpu_accumulated_time *= iteration_rescale_factor; } - data.time_unit = reports[0].time_unit; + data.time_unit = successful_run->time_unit; // user counters for (auto const& kv : counter_stats) { diff --git a/test/repetitions_test.cc b/test/repetitions_test.cc index 80216ab4e1..0673692b64 100644 --- a/test/repetitions_test.cc +++ b/test/repetitions_test.cc @@ -209,6 +209,43 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions\",%csv_report$"}}); ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_mean\",%csv_report$"}}); ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_median\",%csv_report$"}}); ADD_CASES(TC_CSVOut, {{"^\"BM_ImplicitRepetitions_stddev\",%csv_report$"}}); + +// ========================================================================= // +// --------------------- Testing Skipped Repetitions ------------------------ // +// ========================================================================= // + +void BM_SkippedFirstRepetition(benchmark::State& state) { + static int repetition_index = 0; + if (repetition_index++ == 0) { + state.SkipWithError("skipped first repetition"); + return; + } + for (auto _ : state) { + } +} +BENCHMARK(BM_SkippedFirstRepetition)->Repetitions(3); + +ADD_CASES( + TC_ConsoleOut, + {{"^BM_SkippedFirstRepetition/repeats:3[ ]+ERROR OCCURRED: " + "'skipped first repetition'$"}, + {"^BM_SkippedFirstRepetition/repeats:3 %console_report$", MR_Next}, + {"^BM_SkippedFirstRepetition/repeats:3 %console_report$", MR_Next}, + {"^BM_SkippedFirstRepetition/repeats:3_mean %console_report$", MR_Next}, + {"^BM_SkippedFirstRepetition/repeats:3_median %console_report$", MR_Next}, + {"^BM_SkippedFirstRepetition/repeats:3_stddev %console_report$", + MR_Next}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_SkippedFirstRepetition/repeats:3_mean\",$"}, + {"\"run_type\": \"aggregate\",$"}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"aggregate_unit\": \"time\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{"^\"BM_SkippedFirstRepetition/repeats:3_mean\",2,%float,%float," + "ns,,,,,$"}}); } // end namespace // ========================================================================= // From 6408acf50aa7a157a8bc561c367baef0721ccd38 Mon Sep 17 00:00:00 2001 From: Haihan Jiang Date: Tue, 26 May 2026 20:46:27 -0700 Subject: [PATCH 521/561] Clarify DoNotOptimize const-ref warning (#2201) Improve docs for `DoNotOptimize()`, and make it's compile-time diagnostic suggest a possible fix --- docs/user_guide.md | 16 ++++++++++++++++ include/benchmark/utils.h | 23 +++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 14e20047ca..3fed9261d7 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1462,6 +1462,22 @@ known. For example: // while (...) DoNotOptimize(__result__); ``` +Since that is not the behaviour the user intended, +such problematic cases will result in a diagnostic +at compile time. The correct approach, for an expression result, +is to use an intermediate local variable: + +```c++ + // Avoid: may call the deprecated const-reference overload. + while (...) DoNotOptimize(foo(0)); + + // Prefer: materialize the result, then pass the local lvalue. + while (...) { + auto result = foo(0); + DoNotOptimize(result); + } +``` + The second tool for preventing optimizations is `ClobberMemory()`. In essence `ClobberMemory()` forces the compiler to perform all pending writes to global memory. Memory managed by block scope objects must be "escaped" using diff --git a/include/benchmark/utils.h b/include/benchmark/utils.h index 0e4d95dc43..dccd3b218d 100644 --- a/include/benchmark/utils.h +++ b/include/benchmark/utils.h @@ -37,12 +37,15 @@ inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { std::atomic_signal_fence(std::memory_order_acq_rel); } +#define BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG \ + "DoNotOptimize(T const&) can permit undesired compiler optimizations. " \ + "Pass a non-const lvalue instead; if the argument is an expression result, " \ + "store it in a local variable first." + #ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY #if !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER) template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") +BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG) inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { asm volatile("" : : "r,m"(value) : "memory"); } @@ -66,9 +69,7 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { } #elif (__GNUC__ >= 5) template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") +BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG) inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value && (sizeof(Tp) <= sizeof(Tp*))>::type @@ -77,9 +78,7 @@ inline BENCHMARK_ALWAYS_INLINE } template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") +BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG) inline BENCHMARK_ALWAYS_INLINE typename std::enable_if::value || (sizeof(Tp) > sizeof(Tp*))>::type @@ -122,9 +121,7 @@ inline BENCHMARK_ALWAYS_INLINE #elif defined(_MSC_VER) template -BENCHMARK_DEPRECATED_MSG( - "The const-ref version of this method can permit " - "undesired compiler optimizations in benchmarks") +BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG) inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { internal::UseCharPointer(&reinterpret_cast(value)); ClobberMemory(); @@ -148,6 +145,8 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) { } #endif +#undef BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG + } // end namespace benchmark #endif // BENCHMARK_UTILS_H_ From 345756f1aeba6cad00181b431b07e44d34ba374f Mon Sep 17 00:00:00 2001 From: Haihan Jiang Date: Tue, 26 May 2026 21:10:21 -0700 Subject: [PATCH 522/561] Skip perf counter tests when counters are unavailable (#2204) This handles platforms where benchmark is built with libpfm, but the specific counters used by these tests cannot be opened. --- test/perf_counters_gtest.cc | 81 ++++++++++++++++++++----------------- test/perf_counters_test.cc | 35 +++++++++++++--- 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/test/perf_counters_gtest.cc b/test/perf_counters_gtest.cc index c4f287921a..f3fd10bc95 100644 --- a/test/perf_counters_gtest.cc +++ b/test/perf_counters_gtest.cc @@ -1,6 +1,9 @@ #include #include +#include +#include #include +#include #include "../src/perf_counters.h" #include "gmock/gmock.h" @@ -24,26 +27,34 @@ namespace { const char kGenericPerfEvent1[] = "CYCLES"; const char kGenericPerfEvent2[] = "INSTRUCTIONS"; -TEST(PerfCountersTest, Init) { - EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported); +std::set UniqueCounterNames(const PerfCounters& counters) { + return {counters.names().begin(), counters.names().end()}; } -// Generic events will have as many counters as there are CPU PMUs, and each -// will have the same name. In order to make these tests independent of the -// number of CPU PMUs in the system, we uniquify the counter names before -// testing them. -static std::set UniqueCounterNames(const PerfCounters& pc) { - std::set names{pc.names().begin(), pc.names().end()}; - return names; +bool HasRequiredPerfCounters(const std::vector& names) { + if (!PerfCounters::kSupported) { + return false; + } + auto counters = PerfCounters::Create(names); + auto actual_names = UniqueCounterNames(counters); + for (const auto& name : names) { + if (actual_names.find(name) == actual_names.end()) { + return false; + } + } + return true; +} + +TEST(PerfCountersTest, Init) { + EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported); } TEST(PerfCountersTest, OneCounter) { - if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Performance counters not supported.\n"; + if (!HasRequiredPerfCounters({kGenericPerfEvent1})) { + GTEST_SKIP() << "Requested performance counters are not available."; } - EXPECT_TRUE(PerfCounters::Initialize()); - EXPECT_EQ( - UniqueCounterNames(PerfCounters::Create({kGenericPerfEvent1})).size(), 1); + auto counter = PerfCounters::Create({kGenericPerfEvent1}); + EXPECT_EQ(UniqueCounterNames(counter).size(), 1); } TEST(PerfCountersTest, NegativeTest) { @@ -51,7 +62,9 @@ TEST(PerfCountersTest, NegativeTest) { EXPECT_FALSE(PerfCounters::Initialize()); return; } - EXPECT_TRUE(PerfCounters::Initialize()); + if (!HasRequiredPerfCounters({kGenericPerfEvent2, kGenericPerfEvent1})) { + GTEST_SKIP() << "Requested performance counters are not available."; + } // Safety checks // Create() will always create a valid object, even if passed no or // wrong arguments as the new behavior is to warn and drop unsupported @@ -110,10 +123,9 @@ static std::map SnapshotAndCombine( } TEST(PerfCountersTest, Read1Counter) { - if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + if (!HasRequiredPerfCounters({kGenericPerfEvent1})) { + GTEST_SKIP() << "Requested performance counters are not available."; } - EXPECT_TRUE(PerfCounters::Initialize()); auto counters = PerfCounters::Create({kGenericPerfEvent1}); auto values1 = SnapshotAndCombine(counters); EXPECT_EQ(values1.size(), 1); @@ -125,16 +137,14 @@ TEST(PerfCountersTest, Read1Counter) { } TEST(PerfCountersTest, Read1CounterEachCPU) { - if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + if (!HasRequiredPerfCounters({kGenericPerfEvent1})) { + GTEST_SKIP() << "Requested performance counters are not available."; } #ifdef __linux__ - EXPECT_TRUE(PerfCounters::Initialize()); - cpu_set_t saved_set; if (sched_getaffinity(0, sizeof(saved_set), &saved_set) != 0) { // This can happen e.g. if there are more than CPU_SETSIZE CPUs. - GTEST_SKIP() << "Could not save CPU affinity mask.\n"; + GTEST_SKIP() << "Could not save CPU affinity mask."; } for (size_t cpu = 0; cpu != CPU_SETSIZE; ++cpu) { @@ -157,15 +167,14 @@ TEST(PerfCountersTest, Read1CounterEachCPU) { EXPECT_EQ(sched_setaffinity(0, sizeof(saved_set), &saved_set), 0); #else - GTEST_SKIP() << "Test skipped on non-Linux.\n"; + GTEST_SKIP() << "Test skipped on non-Linux."; #endif } TEST(PerfCountersTest, Read2Counters) { - if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + if (!HasRequiredPerfCounters({kGenericPerfEvent1, kGenericPerfEvent2})) { + GTEST_SKIP() << "Requested performance counters are not available."; } - EXPECT_TRUE(PerfCounters::Initialize()); auto counters = PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2}); auto values1 = SnapshotAndCombine(counters); @@ -184,10 +193,9 @@ TEST(PerfCountersTest, Read2Counters) { TEST(PerfCountersTest, ReopenExistingCounters) { // This test works in recent and old Intel hardware, Pixel 3, and Pixel 6. // However we cannot make assumptions beyond 2 HW counters due to Pixel 6. - if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + if (!HasRequiredPerfCounters({kGenericPerfEvent1})) { + GTEST_SKIP() << "Requested performance counters are not available."; } - EXPECT_TRUE(PerfCounters::Initialize()); std::vector kMetrics({kGenericPerfEvent1}); std::vector counters(2); for (auto& counter : counters) { @@ -204,9 +212,8 @@ TEST(PerfCountersTest, CreateExistingMeasurements) { // counters) at this date, // the same as previous test ReopenExistingCounters. if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + GTEST_SKIP() << "Test skipped because libpfm is not supported."; } - EXPECT_TRUE(PerfCounters::Initialize()); // This means we will try 10 counters but we can only guarantee // for sure at this time that only 3 will work. Perhaps in the future @@ -218,6 +225,9 @@ TEST(PerfCountersTest, CreateExistingMeasurements) { // Let's use a ubiquitous counter that is guaranteed to work // on all platforms const std::vector kMetrics{"cycles"}; + if (!HasRequiredPerfCounters(kMetrics)) { + GTEST_SKIP() << "Requested performance counters are not available."; + } // Cannot create a vector of actual objects because the // copy constructor of PerfCounters is deleted - and so is @@ -315,10 +325,9 @@ void measure(size_t threadcount, std::map* before, } TEST(PerfCountersTest, MultiThreaded) { - if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Test skipped because libpfm is not supported."; + if (!HasRequiredPerfCounters({kGenericPerfEvent1, kGenericPerfEvent2})) { + GTEST_SKIP() << "Requested performance counters are not available."; } - EXPECT_TRUE(PerfCounters::Initialize()); std::map before, after; // Notice that this test will work even if we taskset it to a single CPU @@ -357,7 +366,7 @@ TEST(PerfCountersTest, HardwareLimits) { // counters) at this date, // the same as previous test ReopenExistingCounters. if (!PerfCounters::kSupported) { - GTEST_SKIP() << "Test skipped because libpfm is not supported.\n"; + GTEST_SKIP() << "Test skipped because libpfm is not supported."; } EXPECT_TRUE(PerfCounters::Initialize()); diff --git a/test/perf_counters_test.cc b/test/perf_counters_test.cc index d97fa37ec9..d88f6bfd5b 100644 --- a/test/perf_counters_test.cc +++ b/test/perf_counters_test.cc @@ -1,4 +1,7 @@ #include +#include +#include +#include #undef NDEBUG #include "../src/commandlineflags.h" @@ -15,6 +18,27 @@ BM_DECLARE_string(benchmark_perf_counters); } // namespace benchmark namespace { +const char kGenericPerfEvent1[] = "CYCLES"; +const char kGenericPerfEvent2[] = "INSTRUCTIONS"; + +std::set UniqueCounterNames( + const benchmark::internal::PerfCounters& counters) { + return {counters.names().begin(), counters.names().end()}; +} + +bool HasRequiredPerfCounters(const std::vector& names) { + if (!benchmark::internal::PerfCounters::kSupported) { + return false; + } + auto counters = benchmark::internal::PerfCounters::Create(names); + auto actual_names = UniqueCounterNames(counters); + for (const auto& name : names) { + if (actual_names.find(name) == actual_names.end()) { + return false; + } + } + return true; +} void BM_Simple(benchmark::State& state) { for (auto _ : state) { @@ -64,18 +88,18 @@ BENCHMARK(BM_WithPauseResume); ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_WithPauseResume\",$"}}); static void CheckSimple(Results const& e) { - CHECK_COUNTER_VALUE(e, double, "CYCLES", GT, 0); + CHECK_COUNTER_VALUE(e, double, kGenericPerfEvent1, GT, 0); } double withoutPauseResumeInstrCount = 0.0; double withPauseResumeInstrCount = 0.0; void SaveInstrCountWithoutResume(Results const& e) { - withoutPauseResumeInstrCount = e.GetAs("INSTRUCTIONS"); + withoutPauseResumeInstrCount = e.GetAs(kGenericPerfEvent2); } void SaveInstrCountWithResume(Results const& e) { - withPauseResumeInstrCount = e.GetAs("INSTRUCTIONS"); + withPauseResumeInstrCount = e.GetAs(kGenericPerfEvent2); } CHECK_BENCHMARK_RESULTS("BM_Simple", &CheckSimple); @@ -85,10 +109,11 @@ CHECK_BENCHMARK_RESULTS("BM_WithPauseResume", &SaveInstrCountWithResume); int main(int argc, char* argv[]) { benchmark::MaybeReenterWithoutASLR(argc, argv); - if (!benchmark::internal::PerfCounters::kSupported) { + if (!HasRequiredPerfCounters({kGenericPerfEvent1, kGenericPerfEvent2})) { return 0; } - benchmark::FLAGS_benchmark_perf_counters = "CYCLES,INSTRUCTIONS"; + benchmark::FLAGS_benchmark_perf_counters = + std::string(kGenericPerfEvent1) + "," + kGenericPerfEvent2; benchmark::internal::PerfCounters::Initialize(); RunOutputTests(argc, argv); From e27a0c1a50f93de91d5c5fffe89904cd137d0144 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 27 May 2026 10:57:24 +0300 Subject: [PATCH 523/561] Tune AGENTS.md (#2208) Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- AGENTS.md | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 94e51e960d..72f2abe0f0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,20 +1,44 @@ # AI usage +> [!NOTE] +> The modern (as of 2026-06) AI is a misnomer, +> - it is not conscious / not a consciousness, +> - it is not sentient, +> - it is not intelligent, +> - it does not think, +> - it does not understand the code, +> - it is merely a next-token guesser, +> +> ... therefore it is merely an (hyper-) advanced IDE. + +> [!NOTE] +> A contribution is any externally-observable interaction with a project. + +> [!CAUTION] +> Failure to follow the following rules *may* result in repercussions, +> possibly without a prior warning. + +Rules: 1. It is acceptable to use AI when producing contributions. -2. Any and all AI usage must be fully and explictly disclosed - in the PR description and commit message. -3. The modern (as of 2026-06) AI is a misnomer, - it is not intelligent, - it is not sentient, - it does not think, - it does not understand the code, - it is merely a next-token guesser, - therefore it is merely an (hyper-) advanced IDE. -4. Therefore, the actual person contributing - solely bears the whole responsibility for the diff, +> [!WARNING] +> Any and all AI usage **MUST** be fully and explicitly disclosed +> in **every** contribution. +2. All contributions shall be done by conscious, sentient beings. + Fully autonomous contributions by bots are prohibited[^1]. +> [!WARNING] +> Dear contributor, the AI is *your* *tool*, and its output is for *your* +> *consumption*. It is **your** responsibility to consume said output, +> interpret it, and then produce the contribution itself. +> **DO NOT** just query it and post the output, +> *especially* so for all non-code contributions! +3. The contributor (conscious, sentient being) solely bears + the whole responsibility for the contribution, they must understand the problem, and the solution, and be able to constructively argue about it. "well, AI said so, therefore it is" is not an acceptable approach. -5. All contributions shall be done by sentient beings, - fully autonomous contributions by bots, unless explicitly allowed, - is prohibited. + +[^1]: Unless explicitly allowed by maintainers on case-by-case basis + *before* the contribution is submitted, + in which case the bot owner (conscious, sentient being) + is recognized as the de facto contributor. + E.g. https://github.com/apps/dependabot is allowed. From 56c1349d0f684316dc216e2aa1c13427572da638 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 27 May 2026 20:37:17 +0300 Subject: [PATCH 524/561] CONTRIBUTING: actually link to AGENTS.md (#2211) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb73131f42..378c064125 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,7 +56,7 @@ of your first [pull request][]. ## AI usage ## -Please consult [AGENTS.md][] file. +Please consult [AGENTS](AGENTS.md) file. [forking]: https://help.github.com/articles/fork-a-repo [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html From c0f58d3b767a47bd56ece03b447991654de26505 Mon Sep 17 00:00:00 2001 From: Charles Munger Date: Tue, 2 Jun 2026 06:01:31 -0700 Subject: [PATCH 525/561] Disable allocation zeroing in benchmarks on Android (#2214) This is particularly problematic because large allocations partially used can get eagerly memset even if they hit the backing allocator, faulting in a ton of pages, so the behavior can diverge substantially from real in-app performance. --- src/benchmark.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/benchmark.cc b/src/benchmark.cc index e866d296dc..22817851ad 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -30,6 +30,10 @@ #include #endif +#ifdef __ANDROID_NDK__ +#include +#endif + #ifdef BENCHMARK_OS_LINUX #include #endif @@ -902,6 +906,24 @@ void PrintDefaultHelp() { } void Initialize(int* argc, char** argv, void (*HelperPrintf)()) { +#ifdef __ANDROID_NDK__ + // We want standalone android benchmarks to match the performance properties + // of the production environment, so match that configuration here. + + // Android 12 (API level 31) introduced zeroing of allocated memory in bionic + // as a hardening feature; however, this is not enabled for apps. + if (__builtin_available(android 31, *)) { + BM_CHECK_EQ(mallopt(M_BIONIC_ZERO_INIT, 0), 1); + } + + // The default configuration of bionic is to return pages to the OS as soon + // as they are freed. But application processes are configured to run with a + // delay before returning memory to avoid excessive faulting on repeated + // allocation and deallocation, which is common in repeated benchmark runs. + if (__builtin_available(android 27, *)) { + BM_CHECK_EQ(mallopt(M_DECAY_TIME, 1), 1); + } +#endif internal::HelperPrintf = HelperPrintf; internal::ParseCommandLineFlags(argc, argv); internal::LogLevel() = FLAGS_v; From 00ae6b0045979841d355a8fc8549e7a29ea11dc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:41:18 +0100 Subject: [PATCH 526/561] Bump actions/checkout from 6.0.2 to 6.0.3 (#2216) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 93a7e9380d..c5a0335348 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: mount bazel cache uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 331022736d..7764d6e698 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,7 +19,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 81b4170fee..95ae45af1e 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 50a8db79c6..0ec768a0d5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,7 +30,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -77,7 +77,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 6f29b973a6..49709622ec 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index 20a077f096..be128e5678 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 4cfd99c9f1..50499d640f 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index 8c3db2e133..f29ca374dc 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Run analysis uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 547f01c7c1..e2bf518ae3 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index f54ef34f4f..3a4df35407 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: configure msan env if: matrix.sanitizer == 'msan' diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 016a6b2d9e..3cf8064475 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b1b3bb4d12..974b63ce62 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 - name: Install Python 3.12 @@ -38,7 +38,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 From a8460680f0df91fd26205e0931708a26c3b4094d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 10:38:41 +0100 Subject: [PATCH 527/561] Bump astral-sh/setup-uv from 8.1.0 to 8.2.0 (#2217) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.1.0 to 8.2.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/08807647e7069bb48b6ef5acd8ec9567f424441b...fac544c07dec837d0ccb6301d7b5580bf5edae39) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index e2bf518ae3..6aa8196510 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 974b63ce62..4f6105d0e8 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -47,7 +47,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 From 4f38b0a0d4ffbf92c084725cbb32e2d344f7e8d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 09:10:20 +0100 Subject: [PATCH 528/561] Bump pypa/cibuildwheel from 3.4.1 to 4.0.0 (#2218) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.4.1 to 4.0.0. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/8d2b08b68458a16aeb24b64e68a09ab1c8e82084...f03ac7617d6cff873ccf24cc0d567ef5ba5a9e6d) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 4.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4f6105d0e8..4296232d4d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + uses: pypa/cibuildwheel@f03ac7617d6cff873ccf24cc0d567ef5ba5a9e6d # v4.0.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From b5ba9bab85d80f29a161dd634b7d234cf3722f90 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Wed, 10 Jun 2026 17:16:30 +0200 Subject: [PATCH 529/561] Handle missing locale in test on more platforms (#2219) * Add myself to AUTHORS and CONTRIBUTORS * Improve accuracy of locale support check It's much easier to list the two platforms libstdc++ does support locale manipulation on than to try to exhaustively list the myriad platforms where it does not. --- AUTHORS | 1 + CONTRIBUTORS | 1 + test/locale_impermeability_test.cc | 7 ++++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 082422cb81..ab26bb3ad5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,7 @@ Albert Pretorius Alex Steele +Alyssa Ross Andriy Berestovskyy Arne Beer Benjamin King diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f22a988784..88c3b1b327 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -25,6 +25,7 @@ Abhina Sreeskantharajan Albert Pretorius Alex Steele +Alyssa Ross Andriy Berestovskyy Arne Beer Bátor Tallér diff --git a/test/locale_impermeability_test.cc b/test/locale_impermeability_test.cc index 0776fe6114..98982a6505 100644 --- a/test/locale_impermeability_test.cc +++ b/test/locale_impermeability_test.cc @@ -10,9 +10,10 @@ namespace { void BM_ostream(benchmark::State& state) { -#if !defined(__MINGW64__) || defined(__clang__) - // GCC-based versions of MINGW64 do not support locale manipulations, - // don't run the test under them. +#if !defined(__GLIBCXX__) || defined(__GLIBC__) || defined(__DragonFly__) + // libstdc++ only supports locale manipulations on GNU and + // DragonflyBSD platforms at the time of writing, don't run the test + // on other platforms when using libstdc++. std::locale::global(std::locale("en_US.UTF-8")); #endif while (state.KeepRunning()) { From 517b5d5622cfd62e682725341b57001160fb9cac Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Thu, 11 Jun 2026 11:13:38 +0100 Subject: [PATCH 530/561] Fix up windows tests (#2220) * Replace VS 2022 (17) on 2025 with VS 2026 (18) on 2025 * Bring bazel tests in line with cmake wrt minimum times * format BUILD --- .github/workflows/build-and-test.yml | 6 +++--- test/BUILD | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0ec768a0d5..4560b57e0a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -60,7 +60,7 @@ jobs: fail-fast: false matrix: msvc: - - VS-17-2025 + - VS-18-2025 - VS-17-2022 build_type: - Debug @@ -69,9 +69,9 @@ jobs: - shared - static include: - - msvc: VS-17-2025 + - msvc: VS-18-2025 os: windows-2025 - generator: 'Visual Studio 17 2022' + generator: 'Visual Studio 18 2026' - msvc: VS-17-2022 os: windows-2022 generator: 'Visual Studio 17 2022' diff --git a/test/BUILD b/test/BUILD index 9a26970672..d90c002f40 100644 --- a/test/BUILD +++ b/test/BUILD @@ -36,11 +36,16 @@ PER_SRC_COPTS = { TEST_ARGS = ["--benchmark_min_time=0.01s"] PER_SRC_TEST_ARGS = { - "user_counters_tabular_test.cc": ["--benchmark_counters_tabular=true"], + "user_counters_tabular_test.cc": [ + "--benchmark_counters_tabular=true", + "--benchmark_min_time=0.2s", + ], "repetitions_test.cc": [" --benchmark_repetitions=3"], "spec_arg_test.cc": ["--benchmark_filter=BM_NotChosen"], "spec_arg_verbosity_test.cc": ["--v=42"], "complexity_test.cc": ["--benchmark_min_time=1000000x"], + "user_counters_test.cc": ["--benchmark_min_time=0.2s"], + "user_counters_threads_test.cc": ["--benchmark_min_time=0.2s"], } cc_library( From 2b0e960d50afe89ebf57fa442048ddcccb9e649d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:15:54 +0100 Subject: [PATCH 531/561] Bump pypa/cibuildwheel from 4.0.0 to 4.1.0 (#2222) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/f03ac7617d6cff873ccf24cc0d567ef5ba5a9e6d...294735312765b09d24a2fbec22660ce817587d55) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 4.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4296232d4d..8f87e62312 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -50,7 +50,7 @@ jobs: uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 - name: Build wheels on ${{ matrix.os }} using cibuildwheel - uses: pypa/cibuildwheel@f03ac7617d6cff873ccf24cc0d567ef5ba5a9e6d # v4.0.0 + uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0 env: CIBW_BUILD: "cp310-* cp311-* cp312-*" CIBW_BUILD_FRONTEND: "build[uv]" From 1b3abc896c1331293cccb7409f06c0a2d7ae0ef3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:53:13 +0100 Subject: [PATCH 532/561] Bump msys2/setup-msys2 from 2.31.0 to 2.31.1 (#2170) Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.31.0 to 2.31.1. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/cafece8e6baf9247cf9b1bf95097b0b983cc558d...e9898307ac31d1a803454791be09ab9973336e1c) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.31.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4560b57e0a..3046674033 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -117,7 +117,7 @@ jobs: steps: - name: setup msys2 - uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # v2.31.0 + uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1 with: cache: false msystem: ${{ matrix.msys2.msystem }} From eb15fc80dd8a1d2c922fff3551db80dfc6ef2c52 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 15 Jun 2026 14:29:03 +0100 Subject: [PATCH 533/561] Introduce Rust bindings (#2221) * add Rust bindings * clang-format * pre-commit fix * windows static builds * Rust prefers MD on windows * check in lock file to avoid source poisoning * use a rust crate name that isn't taken * add CMake target for running Rust binding tests and integrate into CI * complete crate rename * enable test dependency downloads in Rust bindings CI --- .github/workflows/test_bindings.yml | 28 ++- .gitignore | 3 + CMakeLists.txt | 1 + bindings/rust/Cargo.lock | 301 ++++++++++++++++++++++++++ bindings/rust/Cargo.toml | 13 ++ bindings/rust/build.rs | 40 ++++ bindings/rust/src/ffi.rs | 21 ++ bindings/rust/src/lib.rs | 66 ++++++ bindings/rust/src/rust_api.cc | 26 +++ bindings/rust/src/rust_api.h | 14 ++ bindings/rust/tests/test_benchmark.rs | 16 ++ docs/releasing.md | 7 +- test/CMakeLists.txt | 9 + 13 files changed, 542 insertions(+), 3 deletions(-) create mode 100644 bindings/rust/Cargo.lock create mode 100644 bindings/rust/Cargo.toml create mode 100644 bindings/rust/build.rs create mode 100644 bindings/rust/src/ffi.rs create mode 100644 bindings/rust/src/lib.rs create mode 100644 bindings/rust/src/rust_api.cc create mode 100644 bindings/rust/src/rust_api.h create mode 100644 bindings/rust/tests/test_benchmark.rs diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 3cf8064475..e8639f2b78 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -14,7 +14,7 @@ permissions: jobs: python_bindings: - name: Test GBM Python ${{ matrix.python-version }} bindings on ${{ matrix.os }} + name: Test Python ${{ matrix.python-version }} bindings on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -30,7 +30,31 @@ jobs: uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - - name: Install GBM Python bindings on ${{ matrix.os }} + - name: Install Python bindings on ${{ matrix.os }} run: python -m pip install . - name: Run example on ${{ matrix.os }} under Python ${{ matrix.python-version }} run: python bindings/python/google_benchmark/example.py + + rust_bindings: + name: Test Rust bindings on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + fetch-depth: 0 + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + - name: Install Ninja (macOS) + if: runner.os == 'macOS' + run: brew install ninja + - name: Run Rust tests natively via Cargo + run: cargo test + working-directory: bindings/rust + - name: Run Rust tests via CMake target + run: | + cmake -S . -B build -DBENCHMARK_ENABLE_RUST_BINDINGS=ON -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON + cmake --build build --target test_rust_bindings diff --git a/.gitignore b/.gitignore index bc0c14acd7..53704eba79 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ CMakeSettings.json dist/ *.egg-info* uv.lock + +# Rust build stuff +/bindings/rust/target/ diff --git a/CMakeLists.txt b/CMakeLists.txt index d27698adc8..f08a86e40e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ option(BENCHMARK_ENABLE_GTEST_TESTS "Enable building the unit tests which depend option(BENCHMARK_USE_BUNDLED_GTEST "Use bundled GoogleTest. If disabled, the find_package(GTest) will be used." ON) option(BENCHMARK_ENABLE_LIBPFM "Enable performance counters provided by libpfm" OFF) +option(BENCHMARK_ENABLE_RUST_BINDINGS "Enable testing of the Rust bindings" OFF) # Export only public symbols set(CMAKE_CXX_VISIBILITY_PRESET hidden) diff --git a/bindings/rust/Cargo.lock b/bindings/rust/Cargo.lock new file mode 100644 index 0000000000..c0ed48717e --- /dev/null +++ b/bindings/rust/Cargo.lock @@ -0,0 +1,301 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "cc" +version = "1.2.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "codespan-reporting" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "cxx" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7e" +dependencies = [ + "cc", + "cxx-build", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1e" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283a" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cf" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "google-benchmark-rs" +version = "1.9.5" +dependencies = [ + "cmake", + "cxx", + "cxx-build", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82" +dependencies = [ + "cc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "scratch" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml new file mode 100644 index 0000000000..0a6dda959a --- /dev/null +++ b/bindings/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "google-benchmark-rs" +version = "1.9.5" +edition = "2021" +description = "Rust bindings for google/benchmark" +license = "Apache-2.0" + +[dependencies] +cxx = "1.0" + +[build-dependencies] +cmake = "0.1" +cxx-build = "1.0" diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs new file mode 100644 index 0000000000..02a2f1a14e --- /dev/null +++ b/bindings/rust/build.rs @@ -0,0 +1,40 @@ +fn main() { + let mut config = cmake::Config::new("../../"); + config + .define("BENCHMARK_ENABLE_TESTING", "OFF") + .define("BENCHMARK_ENABLE_LTO", "OFF") + .define("BENCHMARK_ENABLE_WERROR", "OFF") + .build_target("benchmark"); + + // Rust defaults to the Release CRT (/MD) on Windows even in Debug mode. + // Force CMake to use the Release profile so `google/benchmark` uses `/MD`, + // avoiding a mismatch with `cxx_build` (which uses `/MD`). + if cfg!(target_os = "windows") { + config.profile("Release"); + } + + let dst = config.build(); + + println!("cargo:rustc-link-search=native={}/build/src", dst.display()); + println!("cargo:rustc-link-search=native={}/build/src/Debug", dst.display()); + println!("cargo:rustc-link-search=native={}/build/src/Release", dst.display()); + println!("cargo:rustc-link-lib=static=benchmark"); + + cxx_build::bridge("src/ffi.rs") + .file("src/rust_api.cc") + .include("../../include") + .include("src") + .std("c++17") + .define("BENCHMARK_STATIC_DEFINE", None) + .compile("benchmark_rust_ffi"); + + if cfg!(target_os = "windows") { + println!("cargo:rustc-link-lib=shlwapi"); + } + + println!("cargo:rerun-if-changed=src/ffi.rs"); + println!("cargo:rerun-if-changed=src/rust_api.cc"); + println!("cargo:rerun-if-changed=src/rust_api.h"); + println!("cargo:rerun-if-changed=../../src/"); + println!("cargo:rerun-if-changed=../../include/"); +} diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs new file mode 100644 index 0000000000..d8ad766d9e --- /dev/null +++ b/bindings/rust/src/ffi.rs @@ -0,0 +1,21 @@ +#[cxx::bridge] +pub mod ffi { + #[namespace = "benchmark"] + unsafe extern "C++" { + include!("benchmark/benchmark.h"); + + type State; + + fn KeepRunning(self: Pin<&mut State>) -> bool; + fn RunSpecifiedBenchmarks() -> usize; + } + + #[namespace = "benchmark::rust_api"] + unsafe extern "C++" { + include!("rust_api.h"); + + unsafe fn SkipWithError(state: Pin<&mut State>, msg: &str); + unsafe fn RegisterBenchmark(name: &str, func: fn(Pin<&mut State>)); + unsafe fn Initialize(argc: *mut i32, argv: usize); + } +} diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs new file mode 100644 index 0000000000..b13c7ecf67 --- /dev/null +++ b/bindings/rust/src/lib.rs @@ -0,0 +1,66 @@ +pub mod ffi; + +use std::ffi::CString; +use std::os::raw::c_char; +use std::pin::Pin; + +pub struct State<'a> { + #[doc(hidden)] + pub inner: Pin<&'a mut ffi::ffi::State>, +} + +impl<'a> State<'a> { + /// Returns true if the benchmark should continue running. + /// + /// **Note:** `keep_running()` currently has a small per-iteration overhead due to the FFI boundary. + /// In the future, this could be optimized using `KeepRunningBatch` under the hood. + #[inline] + pub fn keep_running(&mut self) -> bool { + self.inner.as_mut().KeepRunning() + } + + pub fn skip_with_error(&mut self, msg: &str) { + unsafe { + ffi::ffi::SkipWithError(self.inner.as_mut(), msg); + } + } +} + +/// Initialize the benchmark library. +/// This should be called before `run_specified_benchmarks`. +pub fn initialize(args: &Vec) { + let mut c_args: Vec = args.iter() + .map(|arg| CString::new(arg.as_str()).unwrap()) + .collect(); + + let mut c_ptrs: Vec<*mut c_char> = c_args.iter_mut() + .map(|c| c.as_ptr() as *mut c_char) + .collect(); + + let mut argc = c_ptrs.len() as i32; + let argv = c_ptrs.as_mut_ptr(); + + unsafe { + ffi::ffi::Initialize(&mut argc as *mut _, argv as usize); + } +} + +#[macro_export] +macro_rules! register_benchmark { + ($name:expr, $func:path) => { + { + fn trampoline(mut state: std::pin::Pin<&mut $crate::ffi::ffi::State>) { + let mut wrapped = $crate::State { inner: state.as_mut() }; + $func(&mut wrapped); + } + unsafe { + $crate::ffi::ffi::RegisterBenchmark($name, trampoline); + } + } + }; +} + +/// Run all registered benchmarks. +pub fn run_specified_benchmarks() -> usize { + ffi::ffi::RunSpecifiedBenchmarks() +} diff --git a/bindings/rust/src/rust_api.cc b/bindings/rust/src/rust_api.cc new file mode 100644 index 0000000000..5efc5fac69 --- /dev/null +++ b/bindings/rust/src/rust_api.cc @@ -0,0 +1,26 @@ +#include "rust_api.h" + +#include + +namespace benchmark { +namespace rust_api { + +void RegisterBenchmark(rust::Str name, rust::Fn func); +void Initialize(int* argc, size_t argv); +void SkipWithError(benchmark::State& state, rust::Str msg); + +void RegisterBenchmark(rust::Str name, rust::Fn func) { + ::benchmark::RegisterBenchmark(std::string(name).c_str(), + [func](benchmark::State& st) { func(st); }); +} + +void Initialize(int* argc, size_t argv) { + ::benchmark::Initialize(argc, (char**)argv); +} + +void SkipWithError(benchmark::State& state, rust::Str msg) { + state.SkipWithError(std::string(msg).c_str()); +} + +} // namespace rust_api +} // namespace benchmark diff --git a/bindings/rust/src/rust_api.h b/bindings/rust/src/rust_api.h new file mode 100644 index 0000000000..17ccd0fd53 --- /dev/null +++ b/bindings/rust/src/rust_api.h @@ -0,0 +1,14 @@ +#pragma once + +#include "benchmark/benchmark.h" +#include "rust/cxx.h" + +namespace benchmark { +namespace rust_api { + +void RegisterBenchmark(rust::Str name, rust::Fn func); +void Initialize(int* argc, size_t argv); +void SkipWithError(benchmark::State& state, rust::Str msg); + +} // namespace rust_api +} // namespace benchmark diff --git a/bindings/rust/tests/test_benchmark.rs b/bindings/rust/tests/test_benchmark.rs new file mode 100644 index 0000000000..025846b654 --- /dev/null +++ b/bindings/rust/tests/test_benchmark.rs @@ -0,0 +1,16 @@ +use google_benchmark_rs::{initialize, register_benchmark, run_specified_benchmarks, State}; + +fn my_benchmark(state: &mut State) { + while state.keep_running() { + // do nothing + } +} + +#[test] +fn test_bindings() { + let args = vec!["--benchmark_format=console".to_string(), "--benchmark_min_time=0.01".to_string()]; + initialize(&args); + register_benchmark!("BM_MyBenchmark", my_benchmark); + let count = run_specified_benchmarks(); + assert!(count > 0); +} diff --git a/docs/releasing.md b/docs/releasing.md index ab664a8640..a58dacd8e5 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -9,7 +9,7 @@ commits between the last annotated tag and HEAD * Pick the most interesting. * Create one last commit that updates the version saved in `CMakeLists.txt`, `MODULE.bazel`, - and `bindings/python/google_benchmark/__init__.py` to the release version you're creating. + `bindings/python/google_benchmark/__init__.py`, and `bindings/rust/Cargo.toml` to the release version you're creating. (This version will be used if benchmark is installed from the archive you'll be creating in the next step.) @@ -28,6 +28,11 @@ module(name = "com_github_google_benchmark", version="1.9.0") __version__ = "1.9.0" ``` +```toml +# bindings/rust/Cargo.toml +version = "1.9.0" +``` + * Create a release through github's interface * Note this will create a lightweight tag. * Update this to an annotated tag: diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 374c09fa3f..588b463f59 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -326,3 +326,12 @@ if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage") " --coverage flag: ${CXX_FLAG_COVERAGE_MESSAGE}") endif() endif() + +if (BENCHMARK_ENABLE_RUST_BINDINGS) + find_program(CARGO_EXECUTABLE cargo REQUIRED) + add_custom_target(test_rust_bindings ALL + COMMAND ${CARGO_EXECUTABLE} test + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bindings/rust + COMMENT "Running Rust bindings tests" + ) +endif() From 64cc7cee5d32b48893e1804f9837aae4106f784b Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:19:28 +0100 Subject: [PATCH 534/561] better rust build/test (#2223) --- .github/workflows/test_bindings.yml | 5 +++-- test/CMakeLists.txt | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index e8639f2b78..eea13b73e2 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -54,7 +54,8 @@ jobs: - name: Run Rust tests natively via Cargo run: cargo test working-directory: bindings/rust - - name: Run Rust tests via CMake target + - name: Run Rust tests via CMake run: | cmake -S . -B build -DBENCHMARK_ENABLE_RUST_BINDINGS=ON -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON - cmake --build build --target test_rust_bindings + cmake --build build + cd build && ctest -R rust_bindings_tests diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 588b463f59..280113ccea 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -329,9 +329,13 @@ endif() if (BENCHMARK_ENABLE_RUST_BINDINGS) find_program(CARGO_EXECUTABLE cargo REQUIRED) - add_custom_target(test_rust_bindings ALL + add_custom_target(build_rust_bindings ALL + COMMAND ${CARGO_EXECUTABLE} build --tests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bindings/rust + COMMENT "Building Rust bindings and tests" + ) + add_test(NAME rust_bindings_tests COMMAND ${CARGO_EXECUTABLE} test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bindings/rust - COMMENT "Running Rust bindings tests" ) endif() From 11ca63f02ff420ae357c0a449cd07f482f1297a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 11:06:27 +0100 Subject: [PATCH 535/561] Bump msys2/setup-msys2 from 2.31.1 to 2.32.0 (#2224) Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.31.1 to 2.32.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/e9898307ac31d1a803454791be09ab9973336e1c...66cd2cce69caa17b53920067426061ca1de3a884) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.32.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3046674033..b6eb0c11ef 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -117,7 +117,7 @@ jobs: steps: - name: setup msys2 - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1 + uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0 with: cache: false msystem: ${{ matrix.msys2.msystem }} From 5bfa2bd77f30e69af99bc511235741220d68fe04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 11:12:29 +0100 Subject: [PATCH 536/561] Bump actions/checkout from 6.0.3 to 7.0.0 (#2225) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b4311f1884172cec0e10...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 4 ++-- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index c5a0335348..1203bd8695 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: mount bazel cache uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 7764d6e698..10a970bb6b 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -19,7 +19,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 95ae45af1e..a270aca769 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b6eb0c11ef..b64594ec40 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,7 +30,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -77,7 +77,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest @@ -131,7 +131,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 49709622ec..acd1a574ab 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index be128e5678..a2540813af 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 50499d640f..c28d8750dc 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index f29ca374dc..a68b21b14e 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Run analysis uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 6aa8196510..e35d2b24f5 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 3a4df35407..5b78eab174 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -19,7 +19,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: configure msan env if: matrix.sanitizer == 'msan' diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index eea13b73e2..ccfd44c59f 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} @@ -43,7 +43,7 @@ jobs: matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - name: Install Rust toolchain diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 8f87e62312..66b8a6a284 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - name: Install Python 3.12 @@ -38,7 +38,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 From 846feb6886a106d8b6d5a1140ce4767c0e5e03b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 12:01:29 +0100 Subject: [PATCH 537/561] Bump scipy from 1.17.1 to 1.18.0 in /tools (#2226) Bumps [scipy](https://github.com/scipy/scipy) from 1.17.1 to 1.18.0. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.17.1...v1.18.0) --- updated-dependencies: - dependency-name: scipy dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 8232756dd6..38bbc8e797 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ numpy == 2.4.6 -scipy == 1.17.1 +scipy == 1.18.0 From ab9383bb49eac305c7e8db372ee2c6f2e1db1c05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 12:23:14 +0100 Subject: [PATCH 538/561] Bump lukka/get-cmake from 4.3.3 to 4.3.4 (#2227) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.3.3 to 4.3.4. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/591817e96fcad43505fb4eae36172462abb3a42e...f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.3.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 10a970bb6b..35bd3245e2 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest + - uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b64594ec40..38d8e1f79b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # latest + - uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # latest - name: configure cmake run: > From 36224c060147e176dbff22f934933a8faf59be2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:05:07 +0100 Subject: [PATCH 539/561] Bump numpy from 2.4.6 to 2.5.0 in /tools (#2228) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.6 to 2.5.0. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.6...v2.5.0) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 38bbc8e797..ea5dca6c6a 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.4.6 +numpy == 2.5.0 scipy == 1.18.0 From 0b88d5c7bfe76adc3fd62178f466e0e68ab235e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 02:41:21 +0300 Subject: [PATCH 540/561] Bump actions/cache from 5.0.5 to 6.0.0 (#2230) Bumps [actions/cache](https://github.com/actions/cache) from 5.0.5 to 6.0.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/27d5ce7f107fe9357f9df03efb73ab90386fccae...2c8a9bd7457de244a408f35966fab2fb45fda9c8) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 1203bd8695..d6a1429426 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: mount bazel cache - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 env: cache-name: bazel-cache with: From bab0f02ecca7b543111bc24e3724e2599dfc8f33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2026 09:17:45 +0100 Subject: [PATCH 541/561] Bump actions/setup-python from 6.2.0 to 6.3.0 (#2232) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.2.0 to 6.3.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/a309ff8b426b58ec0e2a45f0f869d46889d02405...ece7cb06caefa5fff74198d8649806c4678c61a1) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index ccfd44c59f..36a8169f56 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -27,7 +27,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ matrix.python-version }} - name: Install Python bindings on ${{ matrix.os }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 66b8a6a284..df3a8fe4fd 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -19,7 +19,7 @@ jobs: with: fetch-depth: 0 - name: Install Python 3.12 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: "3.12" - run: python -m pip install build @@ -42,7 +42,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 name: Install Python 3.12 with: python-version: "3.12" From eedbb493587ca8f91ff9ea8d2d7e27f6ba0e9214 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:55:17 +0100 Subject: [PATCH 542/561] Bump actions/cache from 6.0.0 to 6.1.0 (#2236) Bumps [actions/cache](https://github.com/actions/cache) from 6.0.0 to 6.1.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/2c8a9bd7457de244a408f35966fab2fb45fda9c8...55cc8345863c7cc4c66a329aec7e433d2d1c52a9) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index d6a1429426..a86949af74 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: mount bazel cache - uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: cache-name: bazel-cache with: From 882336a4b83cba9bf475b312dad410b7e642a2aa Mon Sep 17 00:00:00 2001 From: Sidhartha kumar Date: Tue, 30 Jun 2026 22:54:18 +0530 Subject: [PATCH 543/561] rust bindings: keep argv[0] alive across benchmark reporting (#2237) The Rust binding's initialize() creates temporary CString buffers that are freed on return, but benchmark::Initialize() stores argv[0] as a raw pointer in BenchmarkReporter::Context::executable_name. Later reporter calls dereference freed heap memory (use-after-free). Copy argv[0] into static storage in the C++ bridge before calling benchmark::Initialize(), ensuring the retained pointer remains valid for the process lifetime. AI assistance disclosure: AI tooling was used to assist with auditing, reproducer design, patch drafting, and PR text preparation. --- bindings/rust/src/rust_api.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bindings/rust/src/rust_api.cc b/bindings/rust/src/rust_api.cc index 5efc5fac69..c85997e390 100644 --- a/bindings/rust/src/rust_api.cc +++ b/bindings/rust/src/rust_api.cc @@ -15,7 +15,14 @@ void RegisterBenchmark(rust::Str name, rust::Fn func) { } void Initialize(int* argc, size_t argv) { - ::benchmark::Initialize(argc, (char**)argv); + char** argv_ptr = reinterpret_cast(argv); + if (argc != nullptr && *argc > 0 && argv_ptr != nullptr && + argv_ptr[0] != nullptr) { + static std::string executable_name; + executable_name = argv_ptr[0]; + argv_ptr[0] = executable_name.data(); + } + ::benchmark::Initialize(argc, argv_ptr); } void SkipWithError(benchmark::State& state, rust::Str msg) { From b3a8d2f88e4a4c9e02739e168c9ced0c8434dc23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuna=20K=C4=B1l=C4=B1=C3=A7?= Date: Thu, 2 Jul 2026 11:50:00 +0300 Subject: [PATCH 544/561] docs: document Bazel integration (#2238) * docs: document Bazel integration * fix(docs): avoid pinning current benchmark version --- README.md | 29 ++++++++++++++++ docs/bazel.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.md | 1 + 3 files changed, 122 insertions(+) create mode 100644 docs/bazel.md diff --git a/README.md b/README.md index b60e2d8556..77a2336d96 100644 --- a/README.md +++ b/README.md @@ -273,3 +273,32 @@ Google Benchmark follows CMake's `BUILD_SHARED_LIBS` setting when selecting static or shared library output. On Windows, keep this setting consistent with the rest of the project and make sure the same runtime library configuration is used across the benchmark library and the targets that link it. + +### Usage with Bazel + +If using Bazel with Bzlmod, add Google Benchmark to your `MODULE.bazel` file: + +```starlark +bazel_dep(name = "google_benchmark", version = "") +``` + +Replace `` with the Google Benchmark release version you want to use. + +Then link a `cc_binary` or `cc_test` against one of the provided targets: + +```starlark +load("@rules_cc//cc:defs.bzl", "cc_binary") + +cc_binary( + name = "my_benchmark", + srcs = ["my_benchmark.cc"], + deps = ["@google_benchmark//:benchmark_main"], +) +``` + +Use `@google_benchmark//:benchmark` when your target defines its own `main` +function, including through `BENCHMARK_MAIN()`. Use +`@google_benchmark//:benchmark_main` to use the default Google Benchmark entry +point. + +For WORKSPACE setup and more examples, see [Bazel](docs/bazel.md). diff --git a/docs/bazel.md b/docs/bazel.md new file mode 100644 index 0000000000..b5217a97e8 --- /dev/null +++ b/docs/bazel.md @@ -0,0 +1,92 @@ +# Bazel + +Google Benchmark provides Bazel targets for both the benchmark library and the +optional default `main` function: + +* `@google_benchmark//:benchmark` provides the benchmark library. +* `@google_benchmark//:benchmark_main` provides the default `main` function and + depends on `@google_benchmark//:benchmark`. + +Use `@google_benchmark//:benchmark` when the benchmark target defines its own +`main` function, including through `BENCHMARK_MAIN()`. Use +`@google_benchmark//:benchmark_main` when the benchmark target should use the +default Google Benchmark entry point. + +## Bzlmod + +With Bzlmod enabled, add Google Benchmark to your `MODULE.bazel` file: + +```starlark +bazel_dep(name = "google_benchmark", version = "") +``` + +Replace `` with the Google Benchmark release version you want to use. + +Then depend on the Bazel target from a `cc_binary` or `cc_test`: + +```starlark +load("@rules_cc//cc:defs.bzl", "cc_binary") + +cc_binary( + name = "string_benchmark", + srcs = ["string_benchmark.cc"], + deps = ["@google_benchmark//:benchmark_main"], +) +``` + +The source file should register benchmarks, but it should not call +`BENCHMARK_MAIN()` when linking against `@google_benchmark//:benchmark_main`: + +```c++ +#include +#include + +static void BM_StringCreation(benchmark::State& state) { + for (auto _ : state) { + std::string empty_string; + } +} +BENCHMARK(BM_StringCreation); +``` + +Run the benchmark with Bazel: + +```bash +bazel run //:string_benchmark +``` + +Pass Google Benchmark flags after Bazel's `--` separator: + +```bash +bazel run //:string_benchmark -- --benchmark_filter=StringCreation +``` + +## WORKSPACE + +Projects that still use `WORKSPACE` can declare Google Benchmark as an external +repository and load its dependencies from `bazel/benchmark_deps.bzl`: + +```starlark +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "google_benchmark", + strip_prefix = "benchmark-", + urls = ["https://github.com/google/benchmark/archive/refs/tags/v.tar.gz"], + # Add sha256 for reproducible builds. +) + +load("@google_benchmark//:bazel/benchmark_deps.bzl", "benchmark_deps") + +benchmark_deps() +``` + +Use the same `` value without the leading `v`; the archive URL adds the tag prefix explicitly. + +After declaring the repository, use the same target labels shown above: +`@google_benchmark//:benchmark` or `@google_benchmark//:benchmark_main`. + +## Perf Counters + +When using Bazel, enable libpfm support by adding `--define pfm=1` to the build +or run command. See [Perf Counters](perf_counters.md) for more details. diff --git a/docs/index.md b/docs/index.md index 9cada9688b..af6e88aea1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,7 @@ # Benchmark * [Assembly Tests](AssemblyTests.md) +* [Bazel](bazel.md) * [Dependencies](dependencies.md) * [Perf Counters](perf_counters.md) * [Platform Specific Build Instructions](platform_specific_build_instructions.md) From fb5a752614edf90541322763e9b0bb70a9b55a07 Mon Sep 17 00:00:00 2001 From: dominic <510002+dmah42@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:50:09 +0100 Subject: [PATCH 545/561] Run an autofix pass on github workflows using zizmor (#2233) Zizmor is going to be automatically installed in this repo shortly. To avoid any churn, this is a pre-run to fix up any potential vulnerabilities identified by the tool. --- .github/workflows/bazel.yml | 2 ++ .github/workflows/build-and-test-min-cmake.yml | 2 ++ .../workflows/build-and-test-perfcounters.yml | 2 ++ .github/workflows/build-and-test.yml | 18 +++++++++++++++--- .github/workflows/clang-format-lint.yml | 2 ++ .github/workflows/clang-tidy-lint.yml | 2 ++ .github/workflows/doxygen.yml | 2 ++ .github/workflows/ossf.yml | 4 +++- .github/workflows/sanitizer.yml | 14 +++++++++----- .github/workflows/test_bindings.yml | 2 ++ .github/workflows/wheels.yml | 4 ++++ 11 files changed, 45 insertions(+), 9 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index a86949af74..37840d67ac 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -20,6 +20,8 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: mount bazel cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 35bd3245e2..bd829eb5f6 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -20,6 +20,8 @@ jobs: steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # latest with: diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index a270aca769..3a9a5cdb31 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -24,6 +24,8 @@ jobs: build_type: ['Release', 'Debug'] steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: install libpfm run: | diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 38d8e1f79b..32b0060b9a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -31,6 +31,8 @@ jobs: run: brew install ninja - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: build uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0 @@ -78,21 +80,29 @@ jobs: steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # latest - name: configure cmake run: > - cmake -S . -B ${{ runner.workspace }}/_build/ + cmake -S . -B $env:RUNNER_WORKSPACE/_build/ -G "${{ matrix.generator }}" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBUILD_SHARED_LIBS=${{ matrix.lib == 'shared' }} + env: + RUNNER_WORKSPACE: ${{ runner.workspace }} - name: build - run: cmake --build ${{ runner.workspace }}/_build/ --config ${{ matrix.build_type }} + run: cmake --build $env:RUNNER_WORKSPACE/_build/ --config ${{ matrix.build_type }} + env: + RUNNER_WORKSPACE: ${{ runner.workspace }} - name: test - run: ctest --test-dir ${{ runner.workspace }}/_build/ -C ${{ matrix.build_type }} -VV + run: ctest --test-dir $env:RUNNER_WORKSPACE/_build/ -C ${{ matrix.build_type }} -VV + env: + RUNNER_WORKSPACE: ${{ runner.workspace }} msys2: name: ${{ matrix.os }}.${{ matrix.build_type }}.${{ matrix.lib }}.${{ matrix.msys2.msystem }} @@ -132,6 +142,8 @@ jobs: ninja:p - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false # NOTE: we can't use cmake actions here as we need to do everything in msys2 shell. - name: configure cmake diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index acd1a574ab..afc6a0e01e 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -16,6 +16,8 @@ jobs: steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 with: source: './include/benchmark ./src ./test ./bindings' diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index a2540813af..b2ea505ffb 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -18,6 +18,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: install clang-tidy run: sudo apt update && sudo apt -y install clang-tidy diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index c28d8750dc..843ecc69d4 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -19,6 +19,8 @@ jobs: steps: - name: Fetching sources uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: Installing build dependencies run: | diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index a68b21b14e..325ac9143a 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -13,11 +13,13 @@ jobs: # To write a badge permissions: id-token: write - + runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: Run analysis uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 5b78eab174..ab93581606 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -20,6 +20,8 @@ jobs: steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: configure msan env if: matrix.sanitizer == 'msan' @@ -69,7 +71,9 @@ jobs: echo "EXTRA_CXX_FLAGS=-stdlib=libc++ -L${GITHUB_WORKSPACE}/llvm-build/lib -lc++abi -I${GITHUB_WORKSPACE}/llvm-build/include/c++/v1 -Isystem${GITHUB_WORKSPACE}/llvm-build/include/c++/v1 -Wl,-rpath,${GITHUB_WORKSPACE}/llvm-build/lib" >> $GITHUB_ENV - name: create build environment - run: cmake -E make_directory ${{ runner.workspace }}/_build + run: cmake -E make_directory ${RUNNER_WORKSPACE}/_build + env: + RUNNER_WORKSPACE: ${{ runner.workspace }} - name: configure cmake shell: bash @@ -80,10 +84,10 @@ jobs: -DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF -DBENCHMARK_ENABLE_LIBPFM=OFF -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON - -DCMAKE_C_COMPILER=${{ env.CC }} - -DCMAKE_CXX_COMPILER=${{ env.CXX }} - -DCMAKE_C_FLAGS="${{ env.EXTRA_FLAGS }}" - -DCMAKE_CXX_FLAGS="${{ env.EXTRA_FLAGS }} ${{ env.EXTRA_CXX_FLAGS }}" + -DCMAKE_C_COMPILER=${CC} + -DCMAKE_CXX_COMPILER=${CXX} + -DCMAKE_C_FLAGS="${EXTRA_FLAGS}" + -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} ${EXTRA_CXX_FLAGS}" -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - name: build diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 36a8169f56..8459f9d0a0 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -26,6 +26,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: @@ -46,6 +47,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install Ninja (macOS) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index df3a8fe4fd..0eabd73d49 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -18,6 +18,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false - name: Install Python 3.12 uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: @@ -41,6 +42,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 name: Install Python 3.12 @@ -48,6 +50,8 @@ jobs: python-version: "3.12" - name: Install the latest version of uv uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: false - name: Build wheels on ${{ matrix.os }} using cibuildwheel uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0 From 79d07484f145ae40ac42dc569d393b6396b39cb0 Mon Sep 17 00:00:00 2001 From: anish <145943060+anishesg@users.noreply.github.com> Date: Mon, 6 Jul 2026 08:23:42 -0700 Subject: [PATCH 546/561] fix(linux): prevent infinite re-exec loop under AppArmor (#2239) * fix(linux): prevent infinite re-exec loop under AppArmor The `MaybeReenterWithoutASLR()` function in `src/benchmark.cc` caused infinite execv() loops when running benchmarks under AppArmor-enabled LSMs. The existing fix from #1985 only checked whether personality(ADDR_NO_RANDOMIZE) succeeded in the current process before calling execv(). However, some LSMs like AppArmor can silently reset personality flags during the execve() system call transition, even though the flag was successfully set in the parent process. Additionally, ensure that we actually report that ASLR is still on in case we fail to unset it. Signed-off-by: anish Co-authored-by: anish Co-authored-by: Roman Lebedev --- src/benchmark.cc | 96 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/src/benchmark.cc b/src/benchmark.cc index 22817851ad..7217fc4ed2 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -36,6 +36,7 @@ #ifdef BENCHMARK_OS_LINUX #include +#include #endif #include @@ -43,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -835,11 +837,85 @@ std::make_unsigned_t get_as_unsigned(T v) { } // end namespace internal -void MaybeReenterWithoutASLR(int /*argc*/, char** argv) { +#ifdef BENCHMARK_OS_LINUX +static constexpr const char kTestChildArg[] = "--benchmark_aslr_test_child="; +bool ValidateNoASLRPersonalitySticks(char* argv0) { + // Verify that the personality change survives exec() by testing in a child. + // Some LSMs (e.g., AppArmor) may reset personality flags during execve(), + // even though they were successfully set in the parent process. + // This prevents infinite re-exec loops when the kernel silently resets + // the personality after each exec. + int pipefd[2]; + if (pipe(pipefd) != 0) return false; + + pid_t pid = fork(); + if (pid == -1) { + close(pipefd[0]); + close(pipefd[1]); + return false; + } + + if (pid == 0) { + // Child: prepare to exec with test argument + close(pipefd[0]); + + // Build test argument on stack (safe before exec) + char test_arg[64]; + int test_arg_len = std::snprintf(test_arg, sizeof(test_arg), "%s%d", + kTestChildArg, pipefd[1]); + BM_CHECK_LT(static_cast(test_arg_len), sizeof(test_arg)); + (void)test_arg_len; + + // Simple argv with just the executable and test argument + char* child_argv[] = {argv0, test_arg, nullptr}; + + execv(argv0, child_argv); + // If exec fails, exit + _exit(1); + } + + // Parent: wait for child to report back + close(pipefd[1]); + + char result = 0; + ssize_t nread = read(pipefd[0], &result, 1); + close(pipefd[0]); + + int status; + waitpid(pid, &status, 0); + + // Did we successfully read the result and it indicates ADDR_NO_RANDOMIZE? + return status == 0 && nread == 1 && result == 1; +} +#endif + +void MaybeReenterWithoutASLR(int argc, char** argv) { + (void)argc; + // On e.g. Hexagon simulator, argv may be NULL. if (!argv) return; #ifdef BENCHMARK_OS_LINUX + static constexpr size_t kTestChildArgLen = sizeof(kTestChildArg) - 1; + + // Check if we are a test child process that should report personality and + // exit + if (argc == 2 && + std::strncmp(argv[1], kTestChildArg, kTestChildArgLen) == 0) { + const int write_fd = std::atoi(argv[1] + kTestChildArgLen); + const auto test_personality = personality(0xffffffff); + // Write 1 if ADDR_NO_RANDOMIZE is set, 0 otherwise + char result = + ((test_personality != -1) && + (internal::get_as_unsigned(test_personality) & ADDR_NO_RANDOMIZE)) + ? 1 + : 0; + const auto nbytes = write(write_fd, &result, 1); + close(write_fd); + if (test_personality == -1 || nbytes != 1) std::exit(1); + std::exit(0); + } + const auto curr_personality = personality(0xffffffff); // We should never fail to read-only query the current personality, @@ -861,12 +937,24 @@ void MaybeReenterWithoutASLR(int /*argc*/, char** argv) { // otherwise we will try to reenter infinitely. // This seems impossible, but can happen in some docker configurations. const auto new_personality = personality(0xffffffff); + if (new_personality == -1) return; if ((internal::get_as_unsigned(new_personality) & ADDR_NO_RANDOMIZE) == 0) return; - execv(argv[0], argv); - // The exec() functions return only if an error has occurred, - // in which case we want to just continue as-is. + // Additionally, ensure that the personality change would survive exec(). + if (ValidateNoASLRPersonalitySticks(argv[0])) { + execv(argv[0], argv); + } + + // Personality doesn't survive exec() boundary, or execv() failed. + // We need to try to un-change the personality to "re-enable" ASLR, + // at least so that there is a warning in the output, + // and continue as-is. + const auto restored_personality = + internal::get_as_unsigned(new_personality) & + ~internal::get_as_unsigned(ADDR_NO_RANDOMIZE); + personality(restored_personality); + // This may or may not have failed, but we're out of options here. #else return; #endif From c46905a53044e74a37b49efbe3b2d2852c3d36c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 09:03:07 +0100 Subject: [PATCH 547/561] Bump astral-sh/setup-uv from 8.2.0 to 8.3.0 (#2242) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.2.0 to 8.3.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/fac544c07dec837d0ccb6301d7b5580bf5edae39...d31148d669074a8d0a63714ba94f3201e7020bc3) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index e35d2b24f5..b1085b97b2 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 0eabd73d49..a447decfc8 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -49,7 +49,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0 with: enable-cache: false From 231fffe1f1bbbc28804af92f8c5f5e97f5078ae8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 09:15:25 +0100 Subject: [PATCH 548/561] Bump numpy from 2.5.0 to 2.5.1 in /tools (#2241) Bumps [numpy](https://github.com/numpy/numpy) from 2.5.0 to 2.5.1. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.5.0...v2.5.1) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.5.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index ea5dca6c6a..eaef057fcb 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,2 +1,2 @@ -numpy == 2.5.0 +numpy == 2.5.1 scipy == 1.18.0 From d5acb6946294f21cb21157f813e2ae5e1ade6496 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:10:42 +0100 Subject: [PATCH 549/561] Bump astral-sh/setup-uv from 8.3.0 to 8.3.1 (#2243) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.3.0 to 8.3.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/d31148d669074a8d0a63714ba94f3201e7020bc3...f98e06938123ccabd21905ea5d0069192241f9f1) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index b1085b97b2..3dbc7eca16 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0 + uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index a447decfc8..705f262fb0 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -49,7 +49,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@d31148d669074a8d0a63714ba94f3201e7020bc3 # v8.3.0 + uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1 with: enable-cache: false From c4114ca2b76eefdb48222abff96c12160614b737 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 10:53:30 +0100 Subject: [PATCH 550/561] Bump astral-sh/setup-uv from 8.3.1 to 8.3.2 (#2244) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.3.1 to 8.3.2. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/f98e06938123ccabd21905ea5d0069192241f9f1...11f9893b081a58869d3b5fccaea48c9e9e46f990) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.3.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/wheels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 3dbc7eca16..5a8beb8019 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: with: persist-credentials: false - name: Install uv - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1 + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 with: python-version: 3.12 - name: Run pre-commit checks diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 705f262fb0..9f00e3f0ca 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -49,7 +49,7 @@ jobs: with: python-version: "3.12" - name: Install the latest version of uv - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1 + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 with: enable-cache: false From 8b66b54f7e1bf6b25390dca1dea3f18a40e607f9 Mon Sep 17 00:00:00 2001 From: Tejas Anil Nagmote Date: Thu, 16 Jul 2026 14:16:23 +0530 Subject: [PATCH 551/561] Make --benchmark_list_tests respect --benchmark_format (#2245) * Make --benchmark_list_tests respect --benchmark_format via reporter List() (#1642) * Export FindBenchmarksInternal for shared-library test link; fix include order --- include/benchmark/reporter.h | 13 ++++++ src/benchmark.cc | 4 +- src/benchmark_api_internal.h | 1 + src/csv_reporter.cc | 11 +++++ src/json_reporter.cc | 21 +++++++++ src/reporter.cc | 9 ++++ test/CMakeLists.txt | 1 + test/reporter_list_gtest.cc | 87 ++++++++++++++++++++++++++++++++++++ 8 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 test/reporter_list_gtest.cc diff --git a/include/benchmark/reporter.h b/include/benchmark/reporter.h index be242bec3a..3faa21d385 100644 --- a/include/benchmark/reporter.h +++ b/include/benchmark/reporter.h @@ -36,6 +36,10 @@ namespace benchmark { +namespace internal { +class BenchmarkInstance; +} // namespace internal + struct BENCHMARK_EXPORT BenchmarkName { std::string function_name; std::string args; @@ -132,6 +136,11 @@ class BENCHMARK_EXPORT BenchmarkReporter { virtual void ReportRuns(const std::vector& report) = 0; virtual void Finalize() {} + // Called instead of running the benchmarks when `--benchmark_list_tests` + // is specified, with the benchmarks that were selected to run. The default + // implementation prints one benchmark name per line without any markup. + virtual void List(const std::vector& benchmarks); + void SetOutputStream(std::ostream* out) { assert(out); output_stream_ = out; @@ -181,6 +190,8 @@ class BENCHMARK_EXPORT JSONReporter : public BenchmarkReporter { bool ReportContext(const Context& context) override; void ReportRuns(const std::vector& reports) override; void Finalize() override; + void List( + const std::vector& benchmarks) override; private: void PrintRunData(const Run& run); @@ -194,6 +205,8 @@ class BENCHMARK_EXPORT BENCHMARK_DEPRECATED_MSG( CSVReporter() : printed_header_(false) {} bool ReportContext(const Context& context) override; void ReportRuns(const std::vector& reports) override; + void List( + const std::vector& benchmarks) override; private: void PrintRunData(const Run& run); diff --git a/src/benchmark.cc b/src/benchmark.cc index 7217fc4ed2..91280295e8 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -677,9 +677,7 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, } if (FLAGS_benchmark_list_tests) { - for (auto const& benchmark : benchmarks) { - Out << benchmark.name().str() << "\n"; - } + display_reporter->List(benchmarks); } else { internal::RunBenchmarks(benchmarks, display_reporter, file_reporter); } diff --git a/src/benchmark_api_internal.h b/src/benchmark_api_internal.h index 0f356da2e7..0dd950cbe5 100644 --- a/src/benchmark_api_internal.h +++ b/src/benchmark_api_internal.h @@ -77,6 +77,7 @@ class BenchmarkInstance { callback_function teardown_; }; +BENCHMARK_EXPORT bool FindBenchmarksInternal(const std::string& re, std::vector* benchmarks, std::ostream* Err); diff --git a/src/csv_reporter.cc b/src/csv_reporter.cc index 1665ac58ac..3e21d11f0a 100644 --- a/src/csv_reporter.cc +++ b/src/csv_reporter.cc @@ -18,6 +18,7 @@ #include "benchmark/export.h" #include "benchmark/reporter.h" +#include "benchmark_api_internal.h" #include "check.h" #include "complexity.h" @@ -168,4 +169,14 @@ void CSVReporter::PrintRunData(const Run& run) { Out << '\n'; } +BENCHMARK_EXPORT +void CSVReporter::List( + const std::vector& benchmarks) { + std::ostream& out = GetOutputStream(); + out << "name\n"; + for (const internal::BenchmarkInstance& benchmark : benchmarks) { + out << CsvEscape(benchmark.name().str()) << "\n"; + } +} + } // end namespace benchmark diff --git a/src/json_reporter.cc b/src/json_reporter.cc index ef4636e187..37da17ba03 100644 --- a/src/json_reporter.cc +++ b/src/json_reporter.cc @@ -26,6 +26,7 @@ #include "benchmark/export.h" #include "benchmark/reporter.h" #include "benchmark/types.h" +#include "benchmark_api_internal.h" #include "complexity.h" #include "string_util.h" #include "timers.h" @@ -343,4 +344,24 @@ void JSONReporter::PrintRunData(Run const& run) { out << '\n'; } +void JSONReporter::List( + const std::vector& benchmarks) { + std::ostream& out = GetOutputStream(); + std::string inner_indent(2, ' '); + std::string indent(4, ' '); + std::string entry_indent(6, ' '); + + // Mirror the structure of the regular output so that consumers can read + // the names from the same "benchmarks" array in both modes. + out << "{\n" << inner_indent << "\"benchmarks\": ["; + bool first = true; + for (const internal::BenchmarkInstance& benchmark : benchmarks) { + out << (first ? "\n" : ",\n") << indent << "{\n"; + out << entry_indent << FormatKV("name", benchmark.name().str()) << "\n"; + out << indent << "}"; + first = false; + } + out << "\n" << inner_indent << "]\n}\n"; +} + } // end namespace benchmark diff --git a/src/reporter.cc b/src/reporter.cc index 73ca8d0d56..298ff1a60e 100644 --- a/src/reporter.cc +++ b/src/reporter.cc @@ -23,6 +23,7 @@ #include "benchmark/benchmark_api.h" #include "benchmark/sysinfo.h" +#include "benchmark_api_internal.h" #include "check.h" #include "string_util.h" #include "timers.h" @@ -133,4 +134,12 @@ double BenchmarkReporter::Run::GetAdjustedCPUTime() const { return new_time; } +void BenchmarkReporter::List( + const std::vector& benchmarks) { + std::ostream& out = GetOutputStream(); + for (const internal::BenchmarkInstance& benchmark : benchmarks) { + out << benchmark.name().str() << "\n"; + } +} + } // end namespace benchmark diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 280113ccea..fe88841dd9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -256,6 +256,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS) add_gtest(statistics_gtest) add_gtest(string_util_gtest) add_gtest(perf_counters_gtest) + add_gtest(reporter_list_gtest) add_gtest(time_unit_gtest) add_gtest(min_time_parse_gtest) add_gtest(profiler_manager_gtest) diff --git a/test/reporter_list_gtest.cc b/test/reporter_list_gtest.cc new file mode 100644 index 0000000000..74d5d02dd6 --- /dev/null +++ b/test/reporter_list_gtest.cc @@ -0,0 +1,87 @@ +#include +#include +#include + +#include "../src/benchmark_api_internal.h" +#include "benchmark/benchmark.h" +#include "gtest/gtest.h" + +namespace benchmark { +namespace internal { +namespace { + +void BM_ReporterListDummy(::benchmark::State& state) { + for (auto _ : state) { + } +} + +// Registers two benchmarks (once) and returns the matching instances, the +// same way RunSpecifiedBenchmarks() selects them for --benchmark_list_tests. +const std::vector& ListTestBenchmarks() { + static const std::vector* const benchmarks = [] { + RegisterBenchmark("BM_ReporterListFirst", BM_ReporterListDummy); + RegisterBenchmark("BM_ReporterListSecond", BM_ReporterListDummy); + auto* result = new std::vector(); + std::ostringstream err_stream; + FindBenchmarksInternal("BM_ReporterList.*", result, &err_stream); + return result; + }(); + return *benchmarks; +} + +template +std::string ListedOutput() { + Reporter reporter; + std::ostringstream out; + reporter.SetOutputStream(&out); + reporter.List(ListTestBenchmarks()); + return out.str(); +} + +TEST(ReporterListTest, FindsRegisteredBenchmarks) { + ASSERT_EQ(ListTestBenchmarks().size(), 2u); +} + +TEST(ReporterListTest, DefaultListsOneNamePerLine) { + EXPECT_EQ(ListedOutput(), + "BM_ReporterListFirst\nBM_ReporterListSecond\n"); +} + +TEST(ReporterListTest, JSONListsNamesInBenchmarksArray) { + EXPECT_EQ(ListedOutput(), + "{\n" + " \"benchmarks\": [\n" + " {\n" + " \"name\": \"BM_ReporterListFirst\"\n" + " },\n" + " {\n" + " \"name\": \"BM_ReporterListSecond\"\n" + " }\n" + " ]\n" + "}\n"); +} + +TEST(ReporterListTest, JSONListsNoBenchmarks) { + JSONReporter reporter; + std::ostringstream out; + reporter.SetOutputStream(&out); + reporter.List({}); + EXPECT_EQ(out.str(), + "{\n" + " \"benchmarks\": [\n" + " ]\n" + "}\n"); +} + +TEST(ReporterListTest, CSVListsNameColumn) { + BENCHMARK_DISABLE_DEPRECATED_WARNING + EXPECT_EQ(ListedOutput(), + "name\n" + "\"BM_ReporterListFirst\"\n" + "\"BM_ReporterListSecond\"\n"); + BENCHMARK_RESTORE_DEPRECATED_WARNING +} + +} // namespace +} // namespace internal +} // namespace benchmark From ff954e9ab87c8164c2b45d061281c0efbe22193d Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Fri, 24 Jul 2026 14:57:53 +1200 Subject: [PATCH 552/561] Fix typos, add codespell configuration (#2262) Fix typos --- src/cycleclock.h | 4 ++-- test/output_test_helper.cc | 2 +- tools/gbench/util.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cycleclock.h b/src/cycleclock.h index 23d67d738a..f383b3d6b8 100644 --- a/src/cycleclock.h +++ b/src/cycleclock.h @@ -230,7 +230,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { // Alpha has a cycle counter, the PCC register, but it is an unsigned 32-bit // integer and thus wraps every ~4s, making using it for tick counts // unreliable beyond this time range. The real-time clock is low-precision, - // roughtly ~1ms, but it is the only option that can reasonable count + // roughly ~1ms, but it is the only option that can reasonable count // indefinitely. struct timeval tv; gettimeofday(&tv, nullptr); @@ -238,7 +238,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { #elif defined(__hppa__) || defined(__linux__) || defined(BENCHMARK_OS_WASI) // Fallback for all other architectures with a recent Linux kernel, e.g.: // HP PA-RISC provides a user-readable clock counter (cr16), but - // it's not syncronized across CPUs and only 32-bit wide when programs + // it's not synchronized across CPUs and only 32-bit wide when programs // are built as 32-bit binaries. // Same for SH-4 and possibly others. // Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday diff --git a/test/output_test_helper.cc b/test/output_test_helper.cc index 43a1bfde87..5dc42fb482 100644 --- a/test/output_test_helper.cc +++ b/test/output_test_helper.cc @@ -30,7 +30,7 @@ using TestCaseList = std::vector; using SubMap = std::vector>; TestCaseList& GetTestCaseList(TestCaseID ID) { - // Uses function-local statics to ensure initialization occurs + // Uses function-local static to ensure initialization occurs // before first use. static TestCaseList lists[TC_NumID]; return lists[ID]; diff --git a/tools/gbench/util.py b/tools/gbench/util.py index 2e91006be4..7847e65444 100644 --- a/tools/gbench/util.py +++ b/tools/gbench/util.py @@ -143,7 +143,7 @@ def benchmark_wanted(benchmark): json_schema_version = results["context"]["json_schema_version"] if json_schema_version != 1: print( - f"In {fname}, got unnsupported JSON schema version:" + f"In {fname}, got unsupported JSON schema version:" f" {json_schema_version}, expected 1" ) sys.exit(1) From 2b0bff7444a8df460daab2e5af18bce45ca00657 Mon Sep 17 00:00:00 2001 From: aokblast Date: Sun, 26 Jul 2026 01:40:19 +0800 Subject: [PATCH 553/561] Fix compile error with clang -Werror -Wunused-template (#2268) This sysctl override is only used on some OS'es so it causes compile error with latest LLVM. --- src/sysinfo.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sysinfo.cc b/src/sysinfo.cc index ca32daab5a..a291e10e2b 100644 --- a/src/sysinfo.cc +++ b/src/sysinfo.cc @@ -149,7 +149,7 @@ struct ValueUnion { } template - std::array GetAsArray() { + BENCHMARK_MAYBE_UNUSED std::array GetAsArray() { const int arr_size = sizeof(T) * N; BM_CHECK_LE(arr_size, size); std::array arr; @@ -210,7 +210,8 @@ bool GetSysctl(std::string const& name, Tp* out) { } template -bool GetSysctl(std::string const& name, std::array* out) { +BENCHMARK_MAYBE_UNUSED bool GetSysctl(std::string const& name, + std::array* out) { auto buff = GetSysctlImp(name); if (!buff) return false; *out = buff.GetAsArray(); From e6242692e6a1fa4d0ba9b6b00b9efd59db41069c Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 28 Jul 2026 17:05:16 +0100 Subject: [PATCH 554/561] zizmor should be happy now --- .github/workflows/build-and-test-min-cmake.yml | 5 ++++- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 3 +++ .github/workflows/pre-commit.yml | 3 +++ .github/workflows/sanitizer.yml | 3 +++ .github/workflows/wheels.yml | 3 +++ 6 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index bd829eb5f6..5c698220ca 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +permissions: + contents: read + env: CMAKE_GENERATOR: Ninja @@ -28,7 +31,7 @@ jobs: cmakeVersion: 3.13.0 - name: create build environment - run: cmake -E make_directory ${{ runner.workspace }}/_build + run: cmake -E make_directory $RUNNER_WORKSPACE/_build - name: setup cmake initial cache run: touch compiler-cache.cmake diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 3a9a5cdb31..2c12e60b72 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -33,7 +33,7 @@ jobs: sudo apt -y install libpfm4-dev - name: create build environment - run: cmake -E make_directory ${{ runner.workspace }}/_build + run: cmake -E make_directory $RUNNER_WORKSPACE/_build - name: configure cmake shell: bash diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 32b0060b9a..ef10549a28 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +permissions: + contents: read + env: CMAKE_GENERATOR: Ninja diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 5a8beb8019..0dd49e6fa7 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +permissions: + contents: read + jobs: pre-commit: runs-on: ubuntu-latest diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index ab93581606..6451ba7e7e 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -4,6 +4,9 @@ on: push: {} pull_request: {} +permissions: + contents: read + env: CMAKE_GENERATOR: Ninja UBSAN_OPTIONS: "print_stacktrace=1" diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 9f00e3f0ca..3dbbb194dc 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -9,6 +9,9 @@ on: env: CMAKE_GENERATOR: Ninja +permissions: + contents: read + jobs: build_sdist: name: Build source distribution From 6f09473ddf0fa1f43ab0f0109b272a7c37d32838 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:32:02 +0100 Subject: [PATCH 555/561] Bump lukka/get-cmake from 4.3.4 to 4.4.0 (#2255) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.3.4 to 4.4.0. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9...e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 5c698220ca..2e04c04f98 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -26,7 +26,7 @@ jobs: with: persist-credentials: false - - uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # latest + - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # latest with: cmakeVersion: 3.13.0 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ef10549a28..e25fcb7379 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -86,7 +86,7 @@ jobs: with: persist-credentials: false - - uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # latest + - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # latest - name: configure cmake run: > From fd4cc2ba8b58fe5db397202557c3ec41ffb3e410 Mon Sep 17 00:00:00 2001 From: Dominic Hamon Date: Tue, 28 Jul 2026 17:45:24 +0100 Subject: [PATCH 556/561] pin action to commit hash --- .github/workflows/test_bindings.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 8459f9d0a0..c050e0d879 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -49,7 +49,9 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 + with: + toolchain: stable - name: Install Ninja (macOS) if: runner.os == 'macOS' run: brew install ninja From 76912fe6fbb9219ca8b8e56fa6c100a3afc3c660 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:52:28 +0100 Subject: [PATCH 557/561] Bump actions/setup-python from 6.3.0 to 7.0.0 (#2258) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.3.0 to 7.0.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/ece7cb06caefa5fff74198d8649806c4678c61a1...5fda3b95a4ea91299a34e894583c3862153e4b97) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/test_bindings.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index c050e0d879..09d613a40d 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -28,7 +28,7 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ matrix.python-version }} - name: Install Python bindings on ${{ matrix.os }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 3dbbb194dc..f34408ffa0 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -23,7 +23,7 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Install Python 3.12 - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - run: python -m pip install build @@ -47,7 +47,7 @@ jobs: fetch-depth: 0 persist-credentials: false - - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 name: Install Python 3.12 with: python-version: "3.12" From 9cd398dace6fe40e21cc4d1db0dd9b25962a0ebe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:00:16 +0100 Subject: [PATCH 558/561] Bump actions/checkout from 7.0.0 to 7.0.1 (#2259) Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/build-and-test-min-cmake.yml | 2 +- .github/workflows/build-and-test-perfcounters.yml | 2 +- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/clang-tidy-lint.yml | 2 +- .github/workflows/doxygen.yml | 2 +- .github/workflows/ossf.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/sanitizer.yml | 2 +- .github/workflows/test_bindings.yml | 4 ++-- .github/workflows/wheels.yml | 4 ++-- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 37840d67ac..9b488295a3 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/build-and-test-min-cmake.yml b/.github/workflows/build-and-test-min-cmake.yml index 2e04c04f98..ef00f9d4c9 100644 --- a/.github/workflows/build-and-test-min-cmake.yml +++ b/.github/workflows/build-and-test-min-cmake.yml @@ -22,7 +22,7 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/build-and-test-perfcounters.yml b/.github/workflows/build-and-test-perfcounters.yml index 2c12e60b72..829841e584 100644 --- a/.github/workflows/build-and-test-perfcounters.yml +++ b/.github/workflows/build-and-test-perfcounters.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] build_type: ['Release', 'Debug'] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e25fcb7379..b965c17a7a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -33,7 +33,7 @@ jobs: if: runner.os == 'macOS' run: brew install ninja - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false @@ -82,7 +82,7 @@ jobs: generator: 'Visual Studio 17 2022' steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false @@ -144,7 +144,7 @@ jobs: cmake:p ninja:p - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index afc6a0e01e..e7c2c9d40d 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@bcb4eb2cb0d707ee4f3e5cc3b456eb075f12cf73 # v0.20 diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index b2ea505ffb..42e65cbf72 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 843ecc69d4..5d8246cb51 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetching sources - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/ossf.yml b/.github/workflows/ossf.yml index 325ac9143a..8388c5784d 100644 --- a/.github/workflows/ossf.yml +++ b/.github/workflows/ossf.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 0dd49e6fa7..7cbab26fc8 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Install uv diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 6451ba7e7e..b106c45d76 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -22,7 +22,7 @@ jobs: sanitizer: ['asan', 'ubsan', 'tsan', 'msan'] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/test_bindings.yml b/.github/workflows/test_bindings.yml index 09d613a40d..1899721b2d 100644 --- a/.github/workflows/test_bindings.yml +++ b/.github/workflows/test_bindings.yml @@ -23,7 +23,7 @@ jobs: python-version: [ "3.10", "3.11", "3.12", "3.13" ] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false @@ -44,7 +44,7 @@ jobs: matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f34408ffa0..d8d2fd208a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false @@ -42,7 +42,7 @@ jobs: os: [ubuntu-latest, ubuntu-24.04-arm, macos-15-intel, macos-latest, windows-latest] steps: - name: Check out Google Benchmark - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false From b25d33248549b967b4196e12ee2c91dd7e1e2ff3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:13:53 +0100 Subject: [PATCH 559/561] Bump pypa/gh-action-pypi-publish from 1.14.0 to 1.14.1 (#2260) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.14.0 to 1.14.1. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/cef221092ed1bacb1cc03d23a2d87d1d172e277b...ba38be9e461d3875417946c167d0b5f3d385a247) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-version: 1.14.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d8d2fd208a..4b20127d02 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -88,4 +88,4 @@ jobs: path: dist pattern: dist-* merge-multiple: true - - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 + - uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # release/v1 From fffeac7e863b81941cc82bcc9d7672592b629525 Mon Sep 17 00:00:00 2001 From: Mark Turnpaugh Date: Tue, 28 Jul 2026 14:37:27 -0400 Subject: [PATCH 560/561] Fix thread-safety warnings in Mutex::lock/unlock for newer clang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AppleClang 17+ with -Wthread-safety-analysis errors on Mutex::lock/unlock because std::mutex::lock() is annotated with acquire_capability in libc++. Clang sees mut_ acquired inside lock() (annotated ACQUIRE() for *this), causing a held-at-end-of-function error. Fix by calling pthread_mutex_lock/unlock directly under __clang__, bypassing std::mutex's clang thread-safety annotations. Behavior is identical at runtime — std::mutex::native_handle() returns the underlying pthread_mutex_t*. MSVC does not support -Wthread-safety and does not have pthread.h, so it continues to use std::mutex::lock/unlock unchanged. --- src/mutex.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/mutex.h b/src/mutex.h index bec78d9e5f..5c973e7e81 100644 --- a/src/mutex.h +++ b/src/mutex.h @@ -3,6 +3,9 @@ #include #include +#if defined(__clang__) && !defined(_WIN32) +#include +#endif #include "check.h" @@ -76,8 +79,20 @@ class CAPABILITY("mutex") Mutex { public: Mutex() {} - void lock() ACQUIRE() { mut_.lock(); } - void unlock() RELEASE() { mut_.unlock(); } + void lock() ACQUIRE() { +#if defined(__clang__) && !defined(_WIN32) + pthread_mutex_lock(mut_.native_handle()); +#else + mut_.lock(); +#endif + } + void unlock() RELEASE() { +#if defined(__clang__) && !defined(_WIN32) + pthread_mutex_unlock(mut_.native_handle()); +#else + mut_.unlock(); +#endif + } std::mutex& native_handle() { return mut_; } private: From f04ab7b50aa14921411c243954d95903bb2410eb Mon Sep 17 00:00:00 2001 From: "A.J. Orians" Date: Wed, 22 Jun 2022 13:11:26 -0400 Subject: [PATCH 561/561] Disabled the -fvisibility on benchmark for duo-GTest runner. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f08a86e40e..3031e6a7f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,8 +44,8 @@ option(BENCHMARK_ENABLE_LIBPFM "Enable performance counters provided by libpfm" option(BENCHMARK_ENABLE_RUST_BINDINGS "Enable testing of the Rust bindings" OFF) # Export only public symbols -set(CMAKE_CXX_VISIBILITY_PRESET hidden) -set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) +#set(CMAKE_CXX_VISIBILITY_PRESET hidden) +#set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # As of CMake 3.18, CMAKE_SYSTEM_PROCESSOR is not set properly for MSVC and