From 680721aa14547bf14da1d708e0576ad8339350eb Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 30 Apr 2025 15:40:32 +0200 Subject: [PATCH 1/7] refactor(core): add a codspeed namespace for codspeed core functions --- core/include/codspeed.h | 4 +++ core/src/codspeed.cpp | 3 ++ core/src/uri.cpp | 33 +++++++++++-------- core/src/walltime.cpp | 4 +++ core/test/codspeed.cpp | 11 ++++--- core/test/uri.cpp | 33 ++++++++++++------- .../include/benchmark/benchmark.h | 2 +- google_benchmark/src/benchmark.cc | 11 ++++--- .../src/benchmark_api_internal.cc | 2 +- google_benchmark/src/benchmark_api_internal.h | 2 +- google_benchmark/src/benchmark_runner.cc | 4 +-- 11 files changed, 68 insertions(+), 41 deletions(-) diff --git a/core/include/codspeed.h b/core/include/codspeed.h index e3b6fd2..6a65a06 100644 --- a/core/include/codspeed.h +++ b/core/include/codspeed.h @@ -4,6 +4,8 @@ #include #include +namespace codspeed { + class CodSpeed { public: // Public static method to access the single instance @@ -44,4 +46,6 @@ void generate_codspeed_walltime_report( std::string extract_lambda_namespace(const std::string &pretty_func); std::string sanitize_bench_args(std::string &text); +} // namespace codspeed + #endif // CODSPEED_H diff --git a/core/src/codspeed.cpp b/core/src/codspeed.cpp index 1b90d15..0464d94 100644 --- a/core/src/codspeed.cpp +++ b/core/src/codspeed.cpp @@ -4,6 +4,7 @@ #include #include +namespace codspeed { // Remove any `::` between brackets at the end to not mess with the URI // parsing // FIXME: Remove this bandaid when we migrate to structured benchmark metadata @@ -91,3 +92,5 @@ void CodSpeed::end_benchmark() { std::cerr << action_str << ": " << current_benchmark << group_str << std::endl; } + +} // namespace codspeed diff --git a/core/src/uri.cpp b/core/src/uri.cpp index 2bed0ff..00c8505 100644 --- a/core/src/uri.cpp +++ b/core/src/uri.cpp @@ -1,10 +1,12 @@ #include "codspeed.h" -#include #include +#include + +namespace codspeed { // Example: auto outer::test12::(anonymous class)::operator()() const // Returns: outer::test12:: -std::string extract_namespace_clang(const std::string& pretty_func) { +std::string extract_namespace_clang(const std::string &pretty_func) { std::size_t anon_class_pos = pretty_func.find("::(anonymous class)"); std::size_t space_pos = pretty_func.find(' '); @@ -18,31 +20,34 @@ std::string extract_namespace_clang(const std::string& pretty_func) { // Example: outer::test12:: // Returns: outer::test12:: -std::string extract_namespace_gcc(const std::string& pretty_func) { - auto lambda_pos = pretty_func.find("::"); - if (lambda_pos == std::string::npos) { - return {}; - } +std::string extract_namespace_gcc(const std::string &pretty_func) { + auto lambda_pos = pretty_func.find("::"); + if (lambda_pos == std::string::npos) { + return {}; + } - return pretty_func.substr(0, lambda_pos) + "::"; + return pretty_func.substr(0, lambda_pos) + "::"; } -// Has to pass the pretty function from a lambda: +// Has to pass the pretty function from a lambda: // (([]() { return __PRETTY_FUNCTION__; })()) // -// Returns: An empty string if the namespace could not be extracted, +// Returns: An empty string if the namespace could not be extracted, // otherwise the namespace with a trailing "::" -std::string extract_lambda_namespace(const std::string& pretty_func) { +std::string extract_lambda_namespace(const std::string &pretty_func) { if (pretty_func.find("(anonymous namespace)") != std::string::npos) { - std::cerr << "[ERROR] Anonymous namespace not supported in " << pretty_func << std::endl; + std::cerr << "[ERROR] Anonymous namespace not supported in " << pretty_func + << std::endl; return {}; } #ifdef __clang__ - return extract_namespace_clang(pretty_func); + return extract_namespace_clang(pretty_func); #elif __GNUC__ - return extract_namespace_gcc(pretty_func); + return extract_namespace_gcc(pretty_func); #else #error "Unsupported compiler" #endif } + +} // namespace codspeed diff --git a/core/src/walltime.cpp b/core/src/walltime.cpp index 92bf7c0..58abcfb 100644 --- a/core/src/walltime.cpp +++ b/core/src/walltime.cpp @@ -15,6 +15,8 @@ #endif #include +namespace codspeed { + const double IQR_OUTLIER_FACTOR = 1.5; const double STDEV_OUTLIER_FACTOR = 3.0; @@ -243,3 +245,5 @@ void generate_codspeed_walltime_report( write_codspeed_benchmarks_to_json(codspeed_walltime_benchmarks); } + +} // namespace codspeed diff --git a/core/test/codspeed.cpp b/core/test/codspeed.cpp index c74a1c3..45e5cf0 100644 --- a/core/test/codspeed.cpp +++ b/core/test/codspeed.cpp @@ -8,7 +8,8 @@ TEST(CodSpeedTest, TestSearchAndReplaceBetweenBracketsNamespace) { "examples/google_benchmark/main.cpp::BM_rand_vector"; std::string no_brackets_output = "examples/google_benchmark/main.cpp::BM_rand_vector"; - EXPECT_EQ(sanitize_bench_args(no_brackets_input), no_brackets_output); + EXPECT_EQ(codspeed::sanitize_bench_args(no_brackets_input), + no_brackets_output); std::string brackets_and_no_escaped_type_input = "examples/google_benchmark/" @@ -16,7 +17,7 @@ TEST(CodSpeedTest, TestSearchAndReplaceBetweenBracketsNamespace) { std::string brackets_and_no_escaped_type_output = "examples/google_benchmark/" "template_bench.hpp::BM_Template1_Capture[two_type_test, int, double]"; - EXPECT_EQ(sanitize_bench_args(brackets_and_no_escaped_type_input), + EXPECT_EQ(codspeed::sanitize_bench_args(brackets_and_no_escaped_type_input), brackets_and_no_escaped_type_output); std::string brackets_and_escaped_type_input = @@ -26,7 +27,7 @@ TEST(CodSpeedTest, TestSearchAndReplaceBetweenBracketsNamespace) { "examples/google_benchmark/" "template_bench.hpp::test::BM_Template[std\\:\\:string]"; - EXPECT_EQ(sanitize_bench_args(brackets_and_escaped_type_input), + EXPECT_EQ(codspeed::sanitize_bench_args(brackets_and_escaped_type_input), brackets_and_escaped_type_output); std::string brackets_and_escaped_types_input = @@ -36,7 +37,7 @@ TEST(CodSpeedTest, TestSearchAndReplaceBetweenBracketsNamespace) { "examples/google_benchmark/" "template_bench.hpp::test::BM_Template[std\\:\\:string, std\\:\\:string]"; - EXPECT_EQ(sanitize_bench_args(brackets_and_escaped_types_input), + EXPECT_EQ(codspeed::sanitize_bench_args(brackets_and_escaped_types_input), brackets_and_escaped_types_output); std::string brackets_and_multiple_types_input = @@ -46,6 +47,6 @@ TEST(CodSpeedTest, TestSearchAndReplaceBetweenBracketsNamespace) { "examples/google_benchmark/" "template_bench.hpp::test::BM_Template[std\\:\\:string, int, double]"; - EXPECT_EQ(sanitize_bench_args(brackets_and_multiple_types_input), + EXPECT_EQ(codspeed::sanitize_bench_args(brackets_and_multiple_types_input), brackets_and_multiple_types_output); } diff --git a/core/test/uri.cpp b/core/test/uri.cpp index 47a7ef2..a976322 100644 --- a/core/test/uri.cpp +++ b/core/test/uri.cpp @@ -1,29 +1,38 @@ -#include #include "codspeed.h" +#include // Manual definition (to avoid including it in the public header): -std::string extract_namespace_clang(const std::string& func_str); -std::string extract_namespace_gcc(const std::string& func_str); +namespace codspeed { +std::string extract_namespace_clang(const std::string &func_str); +std::string extract_namespace_gcc(const std::string &func_str); +} // namespace codspeed TEST(UriTest, TestExtractNamespaceClang) { - EXPECT_EQ(extract_namespace_clang("auto outer::test12::(anonymous class)::operator()() const"), "outer::test12::"); - EXPECT_EQ(extract_namespace_clang("auto outer::(anonymous namespace)::test12::(anonymous class)::operator()() const"), "outer::(anonymous namespace)::test12::"); + EXPECT_EQ(codspeed::extract_namespace_clang( + "auto outer::test12::(anonymous class)::operator()() const"), + "outer::test12::"); + EXPECT_EQ(codspeed::extract_namespace_clang( + "auto outer::(anonymous namespace)::test12::(anonymous " + "class)::operator()() const"), + "outer::(anonymous namespace)::test12::"); } TEST(UriTest, TestExtractNamespaceGcc) { - EXPECT_EQ(extract_namespace_gcc("outer::test12::"), "outer::test12::"); - EXPECT_EQ(extract_namespace_gcc("outer::(anonymous namespace)::test12::"), "outer::(anonymous namespace)::test12::"); + EXPECT_EQ(codspeed::extract_namespace_gcc("outer::test12::"), + "outer::test12::"); + EXPECT_EQ(codspeed::extract_namespace_gcc( + "outer::(anonymous namespace)::test12::"), + "outer::(anonymous namespace)::test12::"); } - namespace a { namespace b { namespace c { static std::string pretty_func = ([]() { return __PRETTY_FUNCTION__; })(); TEST(UriTest, TestExtractNamespace) { - EXPECT_EQ(extract_lambda_namespace(pretty_func), "a::b::c::"); -} -} -} + EXPECT_EQ(codspeed::extract_lambda_namespace(pretty_func), "a::b::c::"); } +} // namespace c +} // namespace b +} // namespace a diff --git a/google_benchmark/include/benchmark/benchmark.h b/google_benchmark/include/benchmark/benchmark.h index 48f06e9..1e0b8c1 100644 --- a/google_benchmark/include/benchmark/benchmark.h +++ b/google_benchmark/include/benchmark/benchmark.h @@ -1446,7 +1446,7 @@ class Fixture : public internal::Benchmark { #define CUR_FILE \ std::filesystem::relative(__FILE__, CODSPEED_GIT_ROOT_DIR).string() + "::" #define NAMESPACE \ - (([]() { return extract_lambda_namespace(__PRETTY_FUNCTION__); })()) + (([]() { return codspeed::extract_lambda_namespace(__PRETTY_FUNCTION__); })()) #define STATIC_NAMESPACE_STRING(name) static std::string name = NAMESPACE; #define FILE_AND_NAMESPACE CUR_FILE + NAMESPACE diff --git a/google_benchmark/src/benchmark.cc b/google_benchmark/src/benchmark.cc index 2d27c42..5abd188 100644 --- a/google_benchmark/src/benchmark.cc +++ b/google_benchmark/src/benchmark.cc @@ -352,12 +352,13 @@ void FlushStreams(BenchmarkReporter* reporter) { #ifdef CODSPEED_WALLTIME // We use real time by default, but we could offer CPU time usage as a build // option, open an issue if you need it. -RawWalltimeBenchmark generate_raw_walltime_data(const RunResults& run_results) { - RawWalltimeBenchmark walltime_data; +codspeed::RawWalltimeBenchmark generate_raw_walltime_data( + const RunResults& run_results) { + codspeed::RawWalltimeBenchmark walltime_data; for (const auto& run : run_results.non_aggregates) { walltime_data.uri = run.benchmark_name(); - walltime_data.uri = sanitize_bench_args(walltime_data.uri); + walltime_data.uri = codspeed::sanitize_bench_args(walltime_data.uri); size_t pos = walltime_data.uri.rfind("::"); @@ -529,7 +530,7 @@ void RunBenchmarks(const std::vector& benchmarks, } #ifdef CODSPEED_WALLTIME - std::vector codspeed_walltime_data; + std::vector codspeed_walltime_data; #endif for (size_t repetition_index : repetition_indices) { internal::BenchmarkRunner& runner = runners[repetition_index]; @@ -568,7 +569,7 @@ void RunBenchmarks(const std::vector& benchmarks, Report(display_reporter, file_reporter, run_results); } #ifdef CODSPEED_WALLTIME - generate_codspeed_walltime_report(codspeed_walltime_data); + codspeed::generate_codspeed_walltime_report(codspeed_walltime_data); #endif } display_reporter->Finalize(); diff --git a/google_benchmark/src/benchmark_api_internal.cc b/google_benchmark/src/benchmark_api_internal.cc index 09b8530..c471054 100644 --- a/google_benchmark/src/benchmark_api_internal.cc +++ b/google_benchmark/src/benchmark_api_internal.cc @@ -93,7 +93,7 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx, #ifdef CODSPEED_INSTRUMENTATION State BenchmarkInstance::RunInstrumented( - CodSpeed* codspeed, internal::ThreadTimer* timer, + codspeed::CodSpeed* codspeed, internal::ThreadTimer* timer, internal::ThreadManager* manager, internal::PerfCountersMeasurement* perf_counters_measurement, ProfilerManager* profiler_manager) const { diff --git a/google_benchmark/src/benchmark_api_internal.h b/google_benchmark/src/benchmark_api_internal.h index 0a9446b..b46c8c8 100644 --- a/google_benchmark/src/benchmark_api_internal.h +++ b/google_benchmark/src/benchmark_api_internal.h @@ -59,7 +59,7 @@ class BenchmarkInstance { #ifdef CODSPEED_INSTRUMENTATION State RunInstrumented( - CodSpeed* codspeed, internal::ThreadTimer* timer, + codspeed::CodSpeed* codspeed, internal::ThreadTimer* timer, internal::ThreadManager* manager, internal::PerfCountersMeasurement* perf_counters_measurement, ProfilerManager* profiler_manager) const; diff --git a/google_benchmark/src/benchmark_runner.cc b/google_benchmark/src/benchmark_runner.cc index de6212b..7e85b32 100644 --- a/google_benchmark/src/benchmark_runner.cc +++ b/google_benchmark/src/benchmark_runner.cc @@ -466,8 +466,8 @@ void BenchmarkRunner::DoOneRepetition() { manager.reset(new internal::ThreadManager(b.threads())); internal::ThreadTimer timer = internal::ThreadTimer::Create(); b.Setup(); - State st = b.RunInstrumented(CodSpeed::getInstance(), &timer, manager.get(), - nullptr, nullptr); + State st = b.RunInstrumented(codspeed::CodSpeed::getInstance(), &timer, + manager.get(), nullptr, nullptr); b.Teardown(); return; From ea3bd00313dca4f83c3e27ad050846115043b269 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Tue, 6 May 2025 15:04:49 +0200 Subject: [PATCH 2/7] chore(core): change OFF to off to be inline with other CODSPEED_MODE values --- core/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 0d47f1d..d6b8349 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -52,14 +52,14 @@ target_compile_definitions( INTERFACE -DCODSPEED_GIT_ROOT_DIR="${GIT_ROOT_DIR}" ) -set(CODSPEED_MODE_ALLOWED_VALUES "OFF" "instrumentation" "walltime") -set(CODSPEED_MODE "OFF" CACHE STRING "Build mode for Codspeed") +set(CODSPEED_MODE_ALLOWED_VALUES "off" "instrumentation" "walltime") +set(CODSPEED_MODE "off" CACHE STRING "Build mode for Codspeed") set_property( CACHE CODSPEED_MODE PROPERTY STRINGS ${CODSPEED_MODE_ALLOWED_VALUES} ) -if(NOT CODSPEED_MODE STREQUAL "OFF") +if(NOT CODSPEED_MODE STREQUAL "off") target_compile_definitions(codspeed INTERFACE -DCODSPEED_ENABLED) if(NOT CMAKE_BUILD_TYPE) From 93ab1abc9d313f5796bd4dd2c4bf1a92325785d1 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 30 Apr 2025 16:03:54 +0200 Subject: [PATCH 3/7] feat: add bazel support --- .bazelrc | 1 + .bazelversion | 1 + .github/workflows/ci.yml | 22 +++ .gitignore | 3 + MODULE.bazel | 1 + MODULE.bazel.lock | 126 ++++++++++++++++++ README.md | 4 + core/BUILD | 41 ++++++ core/CMakeLists.txt | 15 ++- core/include/codspeed.h | 4 + core/src/workspace.cpp | 25 ++++ examples/google_benchmark/BUILD.bazel | 7 + flake.nix | 5 +- google_benchmark/BUILD.bazel | 2 +- .../include/benchmark/benchmark.h | 2 +- 15 files changed, 252 insertions(+), 7 deletions(-) create mode 100644 .bazelrc create mode 100644 .bazelversion create mode 100644 MODULE.bazel create mode 100644 MODULE.bazel.lock create mode 100644 core/BUILD create mode 100644 core/src/workspace.cpp create mode 100644 examples/google_benchmark/BUILD.bazel diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..52d5f21 --- /dev/null +++ b/.bazelrc @@ -0,0 +1 @@ +build --//core:codspeed_mode=instrumentation diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..e8be684 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +7.6.1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 828d3aa..d7c12dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,28 @@ jobs: with: name: test_results path: ${{runner.workspace}}/core/build-tests/test/test-results/**/*.json + + cmake-integration-tests: + strategy: + matrix: + codspeed-mode: + - "instrumentation" + - "off" + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Cache build + uses: actions/cache@v3 + with: + path: examples/google_benchmark_cmake/build + key: ${{ runner.os }}-build-${{ matrix.codspeed-mode }}-${{ hashFiles('**/CMakeLists.txt', '**/examples/google_benchmark_cmake/**') }} + + - name: Build and run benchmarks + run: | + bazel run //examples/google_benchmark:my_benchmark instrumentation: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index e060971..75d1d28 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ build/ # Clangd cache .cache/ + +# Bazel output +/bazel-* diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..4874ffc --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1 @@ +bazel_dep(name = "rules_cc", version = "0.0.17") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000..5d4c6dd --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,126 @@ +{ + "lockFileVersion": 13, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/source.json": "14892cc698e02ffedf4967546e6bedb7245015906888d3465fcf27c90a26da10", + "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef", + "https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/source.json": "d7bf14517c1b25b9d9c580b0f8795fceeae08a7590f507b76aace528e941375d", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/googletest/1.14.0/source.json": "2478949479000fdd7de9a3d0107ba2c85bb5f961c3ecb1aa448f52549ce310b5", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.10/source.json": "f22828ff4cf021a6b577f1bf6341cb9dcd7965092a439f64fc1bb3b7a5ae4bd5", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.0/source.json": "1acf3d080c728d42f423fde5422fd0a1a24f44c15908124ce12363a253384193", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/source.json": "4db99b3f55c90ab28d14552aa0632533e3e8e5e9aea0f5c24ac0014282c2a7c5", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1", + "https://bcr.bazel.build/modules/rules_java/7.6.5/source.json": "a805b889531d1690e3c72a7a7e47a870d00323186a9904b36af83aa3d053ee8d", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/source.json": "5abb45cc9beb27b77aec6a65a11855ef2b55d95dfdc358e9f312b78ae0ba32d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/source.json": "d57902c052424dfda0e71646cb12668d39c4620ee0544294d9d941e7d12bc3a9", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", + "https://bcr.bazel.build/modules/rules_python/0.22.1/source.json": "57226905e783bae7c37c2dd662be078728e48fa28ee4324a7eabcafb5a43d014", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.3/source.json": "cd53fe968dc8cd98197c052db3db6d82562960c87b61e7a90ee96f8e4e0dda97", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=", + "usagesDigest": "+hz7IHWN6A1oVJJWNDB6yZRG+RYhF76wAYItpAeIUIg=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_apple_cc_toolchains": { + "bzlFile": "@@apple_support~//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf_toolchains", + "attributes": {} + }, + "local_config_apple_cc": { + "bzlFile": "@@apple_support~//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "apple_support~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@platforms//host:extension.bzl%host_platform": { + "general": { + "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", + "usagesDigest": "hgylFkgWSg0ulUwWZzEM1aIftlUnbmw2ynWLdEfHnZc=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "host_platform": { + "bzlFile": "@@platforms//host:extension.bzl", + "ruleClassName": "host_platform_repo", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [] + } + } + } +} diff --git a/README.md b/README.md index a4edd1f..ba95c30 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,7 @@ This mono-repo contains the integration libraries for using CodSpeed in C++: - [`codspeed-google-benchmark`](./google_benchmark/): Google Benchmark compatibility layer for CodSpeed - [`codspeed-core`](./core/): The CodSpeed core library used to integrate with Codspeed runners + +## Usage + +The library can be used with both [CMake](https://docs.codspeed.io/benchmarks/cpp#cmake) and [Bazel](https://docs.codspeed.io/benchmarks/cpp#bazel). If you need further information to integrate CodSpeed to your project, please feel free to open an issue or ask for help on our discord server. diff --git a/core/BUILD b/core/BUILD new file mode 100644 index 0000000..8489443 --- /dev/null +++ b/core/BUILD @@ -0,0 +1,41 @@ +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") +load("@rules_cc//cc:defs.bzl", "cc_library") + +CODSPEED_VERSION = "1.0.0" + +# Define the codspeed library +cc_library( + name = "codspeed", + srcs = glob(["src/**/*.cpp"] + ["src/**/*.h"] + ["src/**/*.hpp"]), + hdrs = ["include/codspeed.h"], + includes = ["include"], + defines = [ + "CODSPEED_VERSION=\\\"{}\\\"".format(CODSPEED_VERSION), + ] + select({ + ":instrumentation_mode": ["CODSPEED_ENABLED", "CODSPEED_INSTRUMENTATION"], + ":walltime_mode": ["CODSPEED_ENABLED", "CODSPEED_WALLTIME"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], +) + +# Codspeed mode +string_flag( + name = "codspeed_mode", + build_setting_default = "off", + values = [ + "off", + "instrumentation", + "walltime", + ], +) + +config_setting( + name = "instrumentation_mode", + flag_values = {":codspeed_mode": "instrumentation"}, +) + +config_setting( + name = "walltime_mode", + flag_values = {":codspeed_mode": "walltime"}, +) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index d6b8349..7f51fd9 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -12,7 +12,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) include_directories(include) # Add the library -add_library(codspeed src/codspeed.cpp src/walltime.cpp src/uri.cpp) +add_library( + codspeed + src/codspeed.cpp + src/walltime.cpp + src/uri.cpp + src/workspace.cpp +) # Version add_compile_definitions(CODSPEED_VERSION="${CODSPEED_VERSION}") @@ -31,7 +37,7 @@ endif() execute_process( COMMAND git rev-parse --show-toplevel - OUTPUT_VARIABLE GIT_ROOT_DIR + OUTPUT_VARIABLE CODSPEED_ROOT_DIR OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE GIT_COMMAND_RESULT ) @@ -44,13 +50,14 @@ if(NOT GIT_COMMAND_RESULT EQUAL 0) Continuing, but codspeed features will not be useable" ) # Default to user's cmake source directory - set(GIT_ROOT_DIR ${CMAKE_SOURCE_DIR}) + set(CODSPEED_ROOT_DIR ${CMAKE_SOURCE_DIR}) endif() target_compile_definitions( codspeed - INTERFACE -DCODSPEED_GIT_ROOT_DIR="${GIT_ROOT_DIR}" + PRIVATE -DCODSPEED_ROOT_DIR="${CODSPEED_ROOT_DIR}" ) +message(STATUS "Using codspeed root directory: ${CODSPEED_ROOT_DIR}") set(CODSPEED_MODE_ALLOWED_VALUES "off" "instrumentation" "walltime") set(CODSPEED_MODE "off" CACHE STRING "Build mode for Codspeed") diff --git a/core/include/codspeed.h b/core/include/codspeed.h index 6a65a06..05f5ca0 100644 --- a/core/include/codspeed.h +++ b/core/include/codspeed.h @@ -46,6 +46,10 @@ void generate_codspeed_walltime_report( std::string extract_lambda_namespace(const std::string &pretty_func); std::string sanitize_bench_args(std::string &text); +// Gets path relative to workspace root, expected to be called with __FILE__ as +// an argument +std::string get_path_relative_to_workspace(const std::string &path); + } // namespace codspeed #endif // CODSPEED_H diff --git a/core/src/workspace.cpp b/core/src/workspace.cpp new file mode 100644 index 0000000..9322a53 --- /dev/null +++ b/core/src/workspace.cpp @@ -0,0 +1,25 @@ +// Implementation +#include "codspeed.h" +#include +#include + +namespace codspeed { + +std::string get_path_relative_to_workspace(const std::string &path) { + // 1. Check for bazel usage, through the BUILD_WORKSPACE_DIRECTORY env var + // If so, __FILE__ will already be relative to the bazel workspace root + if (std::getenv("BUILD_WORKSPACE_DIRECTORY") != NULL) { + return path; + } + + // 2. If defined, use the specificed value directly +#ifdef CODSPEED_ROOT_DIR + return std::filesystem::relative(path, CODSPEED_ROOT_DIR).string(); +#endif + + // 3. Fallback to bath relative to PWD + return std::filesystem::relative(path, std::filesystem::current_path()) + .string(); +} + +} // namespace codspeed diff --git a/examples/google_benchmark/BUILD.bazel b/examples/google_benchmark/BUILD.bazel new file mode 100644 index 0000000..d30cce5 --- /dev/null +++ b/examples/google_benchmark/BUILD.bazel @@ -0,0 +1,7 @@ +cc_binary( + name = "my_benchmark", + srcs = glob(["*.cpp", "*.hpp"]), + deps = [ + "//google_benchmark:benchmark", + ], +) diff --git a/flake.nix b/flake.nix index 6cb5538..d01a173 100644 --- a/flake.nix +++ b/flake.nix @@ -20,8 +20,11 @@ # Common build inputs for both shells commonBuildInputs = with pkgs; [ gcc - cmake pkg-config + + # Build systems + cmake + bazelisk ]; in diff --git a/google_benchmark/BUILD.bazel b/google_benchmark/BUILD.bazel index 178052c..e944023 100644 --- a/google_benchmark/BUILD.bazel +++ b/google_benchmark/BUILD.bazel @@ -77,7 +77,7 @@ cc_library( "_LARGEFILE_SOURCE", ], visibility = ["//visibility:public"], - deps = select({ + deps = ["//core:codspeed"] + select({ ":perfcounters": ["@libpfm"], "//conditions:default": [], }), diff --git a/google_benchmark/include/benchmark/benchmark.h b/google_benchmark/include/benchmark/benchmark.h index 1e0b8c1..97df506 100644 --- a/google_benchmark/include/benchmark/benchmark.h +++ b/google_benchmark/include/benchmark/benchmark.h @@ -1444,7 +1444,7 @@ class Fixture : public internal::Benchmark { #include #define CUR_FILE \ - std::filesystem::relative(__FILE__, CODSPEED_GIT_ROOT_DIR).string() + "::" + codspeed::get_path_relative_to_workspace(__FILE__) + "::" #define NAMESPACE \ (([]() { return codspeed::extract_lambda_namespace(__PRETTY_FUNCTION__); })()) #define STATIC_NAMESPACE_STRING(name) static std::string name = NAMESPACE; From 72fde2489241605e283459e3f5a1a2cf5e1ce5f8 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Tue, 6 May 2025 15:01:56 +0200 Subject: [PATCH 4/7] chore: add clang-format config to the repo --- .clang-format | 5 +++++ core/include/codspeed.h | 8 ++++---- core/src/codspeed.cpp | 6 ++++-- core/src/measurement.hpp | 5 +++-- core/src/uri.cpp | 7 ++++--- core/src/walltime.cpp | 10 +++++----- core/src/workspace.cpp | 5 +++-- core/test/codspeed.cpp | 1 + core/test/uri.cpp | 11 ++++++----- 9 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e7d00fe --- /dev/null +++ b/.clang-format @@ -0,0 +1,5 @@ +--- +Language: Cpp +BasedOnStyle: Google +PointerAlignment: Left +... diff --git a/core/include/codspeed.h b/core/include/codspeed.h index 05f5ca0..dce56dd 100644 --- a/core/include/codspeed.h +++ b/core/include/codspeed.h @@ -7,7 +7,7 @@ namespace codspeed { class CodSpeed { -public: + public: // Public static method to access the single instance static CodSpeed *getInstance() { static CodSpeed instance; @@ -20,7 +20,7 @@ class CodSpeed { void start_benchmark(const std::string &name); void end_benchmark(); -private: + private: // Private constructor to prevent direct instantiation CodSpeed(); std::vector benchmarked; @@ -50,6 +50,6 @@ std::string sanitize_bench_args(std::string &text); // an argument std::string get_path_relative_to_workspace(const std::string &path); -} // namespace codspeed +} // namespace codspeed -#endif // CODSPEED_H +#endif // CODSPEED_H diff --git a/core/src/codspeed.cpp b/core/src/codspeed.cpp index 0464d94..67badfa 100644 --- a/core/src/codspeed.cpp +++ b/core/src/codspeed.cpp @@ -1,9 +1,11 @@ -#include "measurement.hpp" #include + #include #include #include +#include "measurement.hpp" + namespace codspeed { // Remove any `::` between brackets at the end to not mess with the URI // parsing @@ -93,4 +95,4 @@ void CodSpeed::end_benchmark() { << std::endl; } -} // namespace codspeed +} // namespace codspeed diff --git a/core/src/measurement.hpp b/core/src/measurement.hpp index 25d52bd..94f3b38 100644 --- a/core/src/measurement.hpp +++ b/core/src/measurement.hpp @@ -1,9 +1,10 @@ #ifndef MEASUREMENT_H #define MEASUREMENT_H -#include "callgrind.h" #include +#include "callgrind.h" + inline std::string get_version() { #ifdef CODSPEED_VERSION return {CODSPEED_VERSION}; @@ -29,4 +30,4 @@ inline void measurement_stop(const std::string &name) { CALLGRIND_DUMP_STATS_AT(name.c_str()); }; -#endif // MEASUREMENT_H +#endif // MEASUREMENT_H diff --git a/core/src/uri.cpp b/core/src/uri.cpp index 00c8505..ff58d21 100644 --- a/core/src/uri.cpp +++ b/core/src/uri.cpp @@ -1,7 +1,8 @@ -#include "codspeed.h" #include #include +#include "codspeed.h" + namespace codspeed { // Example: auto outer::test12::(anonymous class)::operator()() const @@ -13,7 +14,7 @@ std::string extract_namespace_clang(const std::string &pretty_func) { if (space_pos == std::string::npos || anon_class_pos == std::string::npos) { return {}; } - space_pos += 1; // Skip the space + space_pos += 1; // Skip the space return pretty_func.substr(space_pos, anon_class_pos - space_pos) + "::"; } @@ -50,4 +51,4 @@ std::string extract_lambda_namespace(const std::string &pretty_func) { #endif } -} // namespace codspeed +} // namespace codspeed diff --git a/core/src/walltime.cpp b/core/src/walltime.cpp index 58abcfb..0dfa80c 100644 --- a/core/src/walltime.cpp +++ b/core/src/walltime.cpp @@ -1,4 +1,3 @@ -#include "codspeed.h" #include #include #include @@ -8,6 +7,8 @@ #include #include #include + +#include "codspeed.h" #ifdef _WIN32 #include #else @@ -49,8 +50,7 @@ struct CodspeedWalltimeBenchmark { double compute_quantile(const std::vector &data, double quantile) { size_t n = data.size(); - if (n == 0) - return 0.0; + if (n == 0) return 0.0; double pos = quantile * (n - 1); size_t k = static_cast(pos); @@ -237,7 +237,7 @@ void generate_codspeed_walltime_report( iqr_outlier_rounds, stdev_outlier_rounds, raw_benchmark.iter_per_round, - 0 // TODO: warmup_iters + 0 // TODO: warmup_iters }; codspeed_walltime_benchmarks.push_back(codspeed_benchmark); @@ -246,4 +246,4 @@ void generate_codspeed_walltime_report( write_codspeed_benchmarks_to_json(codspeed_walltime_benchmarks); } -} // namespace codspeed +} // namespace codspeed diff --git a/core/src/workspace.cpp b/core/src/workspace.cpp index 9322a53..466e510 100644 --- a/core/src/workspace.cpp +++ b/core/src/workspace.cpp @@ -1,8 +1,9 @@ // Implementation -#include "codspeed.h" #include #include +#include "codspeed.h" + namespace codspeed { std::string get_path_relative_to_workspace(const std::string &path) { @@ -22,4 +23,4 @@ std::string get_path_relative_to_workspace(const std::string &path) { .string(); } -} // namespace codspeed +} // namespace codspeed diff --git a/core/test/codspeed.cpp b/core/test/codspeed.cpp index 45e5cf0..9688af6 100644 --- a/core/test/codspeed.cpp +++ b/core/test/codspeed.cpp @@ -1,4 +1,5 @@ #include "codspeed.h" + #include // Manual definition (to avoid including it in the public header): diff --git a/core/test/uri.cpp b/core/test/uri.cpp index a976322..30108f3 100644 --- a/core/test/uri.cpp +++ b/core/test/uri.cpp @@ -1,11 +1,12 @@ -#include "codspeed.h" #include +#include "codspeed.h" + // Manual definition (to avoid including it in the public header): namespace codspeed { std::string extract_namespace_clang(const std::string &func_str); std::string extract_namespace_gcc(const std::string &func_str); -} // namespace codspeed +} // namespace codspeed TEST(UriTest, TestExtractNamespaceClang) { EXPECT_EQ(codspeed::extract_namespace_clang( @@ -33,6 +34,6 @@ static std::string pretty_func = ([]() { return __PRETTY_FUNCTION__; })(); TEST(UriTest, TestExtractNamespace) { EXPECT_EQ(codspeed::extract_lambda_namespace(pretty_func), "a::b::c::"); } -} // namespace c -} // namespace b -} // namespace a +} // namespace c +} // namespace b +} // namespace a From fe032cef6dcb92410f967e1842392de696065258 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Tue, 6 May 2025 14:54:32 +0200 Subject: [PATCH 5/7] ci: add bazel integration tests --- .bazelrc | 2 + .github/workflows/ci.yml | 205 ++++++++---------- .../BUILD.bazel | 0 .../google_benchmark_bazel/fixture_bench.hpp | 1 + examples/google_benchmark_bazel/main.cpp | 1 + .../google_benchmark_bazel/template_bench.hpp | 1 + .../CMakeLists.txt | 0 .../fixture_bench.hpp | 0 .../main.cpp | 0 .../template_bench.hpp | 0 10 files changed, 93 insertions(+), 117 deletions(-) rename examples/{google_benchmark => google_benchmark_bazel}/BUILD.bazel (100%) create mode 120000 examples/google_benchmark_bazel/fixture_bench.hpp create mode 120000 examples/google_benchmark_bazel/main.cpp create mode 120000 examples/google_benchmark_bazel/template_bench.hpp rename examples/{google_benchmark => google_benchmark_cmake}/CMakeLists.txt (100%) rename examples/{google_benchmark => google_benchmark_cmake}/fixture_bench.hpp (100%) rename examples/{google_benchmark => google_benchmark_cmake}/main.cpp (100%) rename examples/{google_benchmark => google_benchmark_cmake}/template_bench.hpp (100%) diff --git a/.bazelrc b/.bazelrc index 52d5f21..ecc6c4e 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1 +1,3 @@ build --//core:codspeed_mode=instrumentation +build --compilation_mode=dbg +build --copt=-O2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7c12dc..1d87aa2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,133 +10,104 @@ jobs: tests: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v3 - - name: Cache build - uses: actions/cache@v3 - with: - path: core/build-tests - key: ${{ runner.os }}-build-tests-${{ hashFiles('**/CMakeLists.txt', '**/examples/google_benchmark/**') }} + - name: Cache build + uses: actions/cache@v3 + with: + path: core/build-tests + key: ${{ runner.os }}-build-tests-${{ hashFiles('**/CMakeLists.txt') }} - - name: Create build directory - run: mkdir -p core/build-tests + - name: Create build directory + run: mkdir -p core/build-tests - - name: Build tests - run: | - cd core/build-tests - cmake .. -DENABLE_TESTS=ON - make -j - - - name: Run tests - run: | - cd core/build-tests - GTEST_OUTPUT=json:test-results/ ctest - - - name: Upload test results - uses: actions/upload-artifact@v4 - if: failure() - with: - name: test_results - path: ${{runner.workspace}}/core/build-tests/test/test-results/**/*.json + - name: Build tests + run: | + cd core/build-tests + cmake .. -DENABLE_TESTS=ON + make -j + + - name: Run tests + run: | + cd core/build-tests + GTEST_OUTPUT=json:test-results/ ctest + + - name: Upload test results + uses: actions/upload-artifact@v4 + if: failure() + with: + name: test_results + path: ${{runner.workspace}}/core/build-tests/test/test-results/**/*.json cmake-integration-tests: strategy: matrix: - codspeed-mode: - - "instrumentation" - - "off" - runs-on: ubuntu-latest - + include: + - codspeed-mode: "instrumentation" + runner: "ubuntu-latest" + - codspeed-mode: "walltime" + runner: "codspeed-macro" + - codspeed-mode: "off" + runner: "ubuntu-latest" + runs-on: ${{ matrix.runner }} steps: - - name: Checkout code - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v3 - - name: Cache build - uses: actions/cache@v3 - with: - path: examples/google_benchmark_cmake/build - key: ${{ runner.os }}-build-${{ matrix.codspeed-mode }}-${{ hashFiles('**/CMakeLists.txt', '**/examples/google_benchmark_cmake/**') }} + - name: Cache build + uses: actions/cache@v3 + with: + path: examples/google_benchmark_cmake/build + key: ${{ runner.os }}-build-${{ matrix.codspeed-mode }}-${{ hashFiles('**/CMakeLists.txt') }} - - name: Build and run benchmarks - run: | - bazel run //examples/google_benchmark:my_benchmark - - instrumentation: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Cache build - uses: actions/cache@v3 - with: - path: examples/google_benchmark/build-instrumentation - key: ${{ runner.os }}-build-instrumentation-${{ hashFiles('**/CMakeLists.txt', '**/examples/google_benchmark/**') }} - - - name: Create build directory - run: mkdir -p examples/google_benchmark/build-instrumentation - - - name: Build instrumentation benchmark example - run: | - cd examples/google_benchmark/build-instrumentation - cmake -DCODSPEED_MODE=instrumentation .. - make -j - - - name: Run the benchmarks - uses: CodSpeedHQ/action@main - with: - run: examples/google_benchmark/build-instrumentation/benchmark_example - token: ${{ secrets.CODSPEED_TOKEN }} - - walltime: - runs-on: codspeed-macro - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Cache build - uses: actions/cache@v3 - with: - path: examples/google_benchmark/build-walltime - key: ${{ runner.os }}-build-walltime-${{ hashFiles('**/CMakeLists.txt', '**/examples/google_benchmark/**') }} - - - name: Create build directory - run: mkdir -p examples/google_benchmark/build-walltime - - - name: Build walltime benchmark example - run: | - cd examples/google_benchmark/build-walltime - cmake -DCODSPEED_MODE=walltime .. - make -j - - - name: Run the benchmarks - uses: CodSpeedHQ/action@main - with: - run: examples/google_benchmark/build-walltime/benchmark_example - token: ${{ secrets.CODSPEED_TOKEN }} - - - build-no-codspeed: - runs-on: ubuntu-latest + - name: Create build directory + run: mkdir -p examples/google_benchmark_cmake/build + - name: Build benchmark example + run: | + cd examples/google_benchmark_cmake/build + cmake -DCODSPEED_MODE=${{ matrix.codspeed-mode }} .. + make -j + + - name: Run the benchmarks + uses: CodSpeedHQ/action@main + if: matrix.codspeed-mode != 'off' + with: + run: examples/google_benchmark_cmake/build/benchmark_example + token: ${{ secrets.CODSPEED_TOKEN }} + + bazel-integration-tests: + strategy: + matrix: + include: + - codspeed-mode: "instrumentation" + runner: "ubuntu-latest" + - codspeed-mode: "walltime" + runner: "codspeed-macro" + - codspeed-mode: "off" + runner: "ubuntu-latest" + runs-on: ${{ matrix.runner }} steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Cache build - uses: actions/cache@v3 - with: - path: examples/google_benchmark/build-no-codspeed - key: ${{ runner.os }}-build-no-codspeed-${{ hashFiles('**/CMakeLists.txt', '**/examples/google_benchmark/**') }} + - uses: actions/checkout@v4 + + - name: Set up Bazel + uses: bazel-contrib/setup-bazel@0.14.0 + with: + # Avoid downloading Bazel every time. + bazelisk-cache: true + # Store build cache per workflow. + disk-cache: ${{ github.workflow }} + # Share repository cache between workflows. + repository-cache: true - - name: Create build directory - run: mkdir -p examples/google_benchmark/build-no-codspeed - - - name: Build benchmark example without codspeed - run: | - cd examples/google_benchmark/build-no-codspeed - cmake .. - make -j + - name: Build and run benchmarks + run: | + bazel build //examples/google_benchmark_bazel:my_benchmark --//core:codspeed_mode=${{ matrix.codspeed-mode }} + + - name: Run the benchmarks + uses: CodSpeedHQ/action@main + if: matrix.codspeed-mode != 'off' + with: + run: bazel run //examples/google_benchmark_bazel:my_benchmark --//core:codspeed_mode=${{ matrix.codspeed-mode }} + token: ${{ secrets.CODSPEED_TOKEN }} diff --git a/examples/google_benchmark/BUILD.bazel b/examples/google_benchmark_bazel/BUILD.bazel similarity index 100% rename from examples/google_benchmark/BUILD.bazel rename to examples/google_benchmark_bazel/BUILD.bazel diff --git a/examples/google_benchmark_bazel/fixture_bench.hpp b/examples/google_benchmark_bazel/fixture_bench.hpp new file mode 120000 index 0000000..d88ad24 --- /dev/null +++ b/examples/google_benchmark_bazel/fixture_bench.hpp @@ -0,0 +1 @@ +../google_benchmark_cmake/fixture_bench.hpp \ No newline at end of file diff --git a/examples/google_benchmark_bazel/main.cpp b/examples/google_benchmark_bazel/main.cpp new file mode 120000 index 0000000..f56750a --- /dev/null +++ b/examples/google_benchmark_bazel/main.cpp @@ -0,0 +1 @@ +../google_benchmark_cmake/main.cpp \ No newline at end of file diff --git a/examples/google_benchmark_bazel/template_bench.hpp b/examples/google_benchmark_bazel/template_bench.hpp new file mode 120000 index 0000000..1e9234d --- /dev/null +++ b/examples/google_benchmark_bazel/template_bench.hpp @@ -0,0 +1 @@ +../google_benchmark_cmake/template_bench.hpp \ No newline at end of file diff --git a/examples/google_benchmark/CMakeLists.txt b/examples/google_benchmark_cmake/CMakeLists.txt similarity index 100% rename from examples/google_benchmark/CMakeLists.txt rename to examples/google_benchmark_cmake/CMakeLists.txt diff --git a/examples/google_benchmark/fixture_bench.hpp b/examples/google_benchmark_cmake/fixture_bench.hpp similarity index 100% rename from examples/google_benchmark/fixture_bench.hpp rename to examples/google_benchmark_cmake/fixture_bench.hpp diff --git a/examples/google_benchmark/main.cpp b/examples/google_benchmark_cmake/main.cpp similarity index 100% rename from examples/google_benchmark/main.cpp rename to examples/google_benchmark_cmake/main.cpp diff --git a/examples/google_benchmark/template_bench.hpp b/examples/google_benchmark_cmake/template_bench.hpp similarity index 100% rename from examples/google_benchmark/template_bench.hpp rename to examples/google_benchmark_cmake/template_bench.hpp From 352b991b1116635175717a2031c437b28f8f660b Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Tue, 6 May 2025 17:56:58 +0200 Subject: [PATCH 6/7] feat!(google_benchmark): improve location of valgrind trapdoors --- core/BUILD | 2 +- core/CMakeLists.txt | 2 +- core/{src => include}/callgrind.h | 0 core/{src => include}/measurement.hpp | 5 +-- core/{src => include}/valgrind.h | 0 core/src/codspeed.cpp | 1 - .../include/benchmark/benchmark.h | 32 ++++++++++++++++--- google_benchmark/src/benchmark.cc | 10 +++++- .../src/benchmark_api_internal.cc | 11 ++++--- 9 files changed, 47 insertions(+), 16 deletions(-) rename core/{src => include}/callgrind.h (100%) rename core/{src => include}/measurement.hpp (79%) rename core/{src => include}/valgrind.h (100%) diff --git a/core/BUILD b/core/BUILD index 8489443..2c9996e 100644 --- a/core/BUILD +++ b/core/BUILD @@ -7,7 +7,7 @@ CODSPEED_VERSION = "1.0.0" cc_library( name = "codspeed", srcs = glob(["src/**/*.cpp"] + ["src/**/*.h"] + ["src/**/*.hpp"]), - hdrs = ["include/codspeed.h"], + hdrs = glob(["include/**/*.h"] + ["include/**/*.hpp"]), includes = ["include"], defines = [ "CODSPEED_VERSION=\\\"{}\\\"".format(CODSPEED_VERSION), diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 7f51fd9..edfb792 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -32,7 +32,7 @@ target_include_directories( # Disable valgrind compilation errors if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # Disable the old-style-cast warning for the specific target - target_compile_options(codspeed PRIVATE -Wno-old-style-cast) + target_compile_options(codspeed INTERFACE -Wno-old-style-cast) endif() execute_process( diff --git a/core/src/callgrind.h b/core/include/callgrind.h similarity index 100% rename from core/src/callgrind.h rename to core/include/callgrind.h diff --git a/core/src/measurement.hpp b/core/include/measurement.hpp similarity index 79% rename from core/src/measurement.hpp rename to core/include/measurement.hpp index 94f3b38..e34ab62 100644 --- a/core/src/measurement.hpp +++ b/core/include/measurement.hpp @@ -20,12 +20,13 @@ inline void measurement_set_metadata() { CALLGRIND_DUMP_STATS_AT(metadata.c_str()); } -inline void measurement_start() { +__attribute__((always_inline)) inline void measurement_start() { CALLGRIND_ZERO_STATS; CALLGRIND_START_INSTRUMENTATION; } -inline void measurement_stop(const std::string &name) { +__attribute__((always_inline)) inline void measurement_stop( + const std::string &name) { CALLGRIND_STOP_INSTRUMENTATION; CALLGRIND_DUMP_STATS_AT(name.c_str()); }; diff --git a/core/src/valgrind.h b/core/include/valgrind.h similarity index 100% rename from core/src/valgrind.h rename to core/include/valgrind.h diff --git a/core/src/codspeed.cpp b/core/src/codspeed.cpp index 67badfa..72ef873 100644 --- a/core/src/codspeed.cpp +++ b/core/src/codspeed.cpp @@ -82,7 +82,6 @@ void CodSpeed::start_benchmark(const std::string &name) { } current_benchmark = uri; - measurement_start(); } void CodSpeed::end_benchmark() { diff --git a/google_benchmark/include/benchmark/benchmark.h b/google_benchmark/include/benchmark/benchmark.h index 97df506..0bca99f 100644 --- a/google_benchmark/include/benchmark/benchmark.h +++ b/google_benchmark/include/benchmark/benchmark.h @@ -183,6 +183,13 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); #include "benchmark/export.h" +#ifdef CODSPEED_ENABLED +#include +#include + +#include +#endif // CODSPEED_ENABLED + #if defined(_MSC_VER) #include // for _ReadWriteBarrier #endif @@ -939,6 +946,9 @@ class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { public: const IterationCount max_iterations; +#ifdef CODSPEED_INSTRUMENTATION + codspeed::CodSpeed *codspeed_; +#endif private: bool started_; @@ -959,7 +969,12 @@ class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State { const std::vector& ranges, int thread_i, int n_threads, internal::ThreadTimer* timer, internal::ThreadManager* manager, internal::PerfCountersMeasurement* perf_counters_measurement, - ProfilerManager* profiler_manager); + ProfilerManager* profiler_manager + #ifdef CODSPEED_INSTRUMENTATION + , + codspeed::CodSpeed *codspeed = NULL + #endif + ); void StartKeepRunning(); // Implementation of KeepRunning() and KeepRunningBatch(). @@ -1049,6 +1064,11 @@ struct State::StateIterator { BENCHMARK_ALWAYS_INLINE bool operator!=(StateIterator const&) const { if (BENCHMARK_BUILTIN_EXPECT(cached_ != 0, true)) return true; +#ifdef CODSPEED_INSTRUMENTATION + if (parent_->codspeed_ != NULL) { + parent_->codspeed_->end_benchmark(); + } +#endif parent_->FinishKeepRunning(); return false; } @@ -1063,6 +1083,12 @@ inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::begin() { } inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { StartKeepRunning(); +#ifdef CODSPEED_INSTRUMENTATION + if (this->codspeed_ != NULL) { + this->codspeed_->start_benchmark(name_); + measurement_start(); + } +#endif return StateIterator(); } @@ -1439,10 +1465,6 @@ class Fixture : public internal::Benchmark { n) [[maybe_unused]] #ifdef CODSPEED_ENABLED -#include - -#include - #define CUR_FILE \ codspeed::get_path_relative_to_workspace(__FILE__) + "::" #define NAMESPACE \ diff --git a/google_benchmark/src/benchmark.cc b/google_benchmark/src/benchmark.cc index 5abd188..8936a17 100644 --- a/google_benchmark/src/benchmark.cc +++ b/google_benchmark/src/benchmark.cc @@ -174,10 +174,18 @@ 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, - ProfilerManager* profiler_manager) + ProfilerManager* profiler_manager +#ifdef CODSPEED_INSTRUMENTATION + , + codspeed::CodSpeed* codspeed +#endif + ) : total_iterations_(0), batch_leftover_(0), max_iterations(max_iters), +#ifdef CODSPEED_INSTRUMENTATION + codspeed_(codspeed), +#endif started_(false), finished_(false), skipped_(internal::NotSkipped), diff --git a/google_benchmark/src/benchmark_api_internal.cc b/google_benchmark/src/benchmark_api_internal.cc index c471054..feeb65c 100644 --- a/google_benchmark/src/benchmark_api_internal.cc +++ b/google_benchmark/src/benchmark_api_internal.cc @@ -97,18 +97,19 @@ State BenchmarkInstance::RunInstrumented( internal::ThreadManager* manager, internal::PerfCountersMeasurement* perf_counters_measurement, ProfilerManager* profiler_manager) const { - State st(name_.function_name, 1, args_, 0, 1, timer, manager, - perf_counters_measurement, profiler_manager); // Do one repetition to avoid flakiness due to inconcistencies in CPU cache // from execution order internal::ThreadTimer warmup_timer = internal::ThreadTimer::Create(); State warmup_state(name_.function_name, 1, args_, 0, 1, &warmup_timer, - manager, perf_counters_measurement, profiler_manager); + manager, perf_counters_measurement, profiler_manager, + NULL); benchmark_.Run(warmup_state); - codspeed->start_benchmark(name().str()); + + State st(name().str(), 1, args_, 0, 1, timer, manager, + perf_counters_measurement, profiler_manager, codspeed); + ; benchmark_.Run(st); - codspeed->end_benchmark(); return st; } #endif From bf3068412ac8fd1692e3745499e3ebb9fe06e124 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 7 May 2025 15:37:42 +0200 Subject: [PATCH 7/7] chore: bump chore library version --- CONTRIBUTING.md | 2 +- core/BUILD | 2 +- core/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec13429..b962924 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,4 +4,4 @@ For now, releasing is done manually, by tagging a git rev with vX.Y.Z. -When releasing a new version, please make sure the [version](https://github.com/CodSpeedHQ/codspeed-cpp/blob/fix-walltime-pid/core/CMakeLists.txt#L3) is updated in the `core/CMakeLists.txt` file to match the pushed version +When releasing a new version, please make sure the version is updated in the [`core/CMakeLists.txt`](https://github.com/CodSpeedHQ/codspeed-cpp/blob/main/core/CMakeLists.txt#L3) and [`core/BUILD`](https://github.com/CodSpeedHQ/codspeed-cpp/blob/main/core/BUILD#L4) files to match the pushed version diff --git a/core/BUILD b/core/BUILD index 2c9996e..3c13b0d 100644 --- a/core/BUILD +++ b/core/BUILD @@ -1,7 +1,7 @@ load("@bazel_skylib//rules:common_settings.bzl", "string_flag") load("@rules_cc//cc:defs.bzl", "cc_library") -CODSPEED_VERSION = "1.0.0" +CODSPEED_VERSION = "1.1.0" # Define the codspeed library cc_library( diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index edfb792..5fc3df9 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) -set(CODSPEED_VERSION 1.0.1) +set(CODSPEED_VERSION 1.1.0) project(codspeed VERSION ${CODSPEED_VERSION} LANGUAGES CXX)