diff --git a/.github/workflows/bvt-appleclang.yml b/.github/workflows/bvt-appleclang.yml index 2aebf90..d3b84b9 100644 --- a/.github/workflows/bvt-appleclang.yml +++ b/.github/workflows/bvt-appleclang.yml @@ -20,6 +20,10 @@ jobs: - name: build and run test with AppleClang run: | - cmake -B build + cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build -j ctest --test-dir build -j + + - name: run benchmarks + run: | + ./build/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true diff --git a/.github/workflows/bvt-clang.yml b/.github/workflows/bvt-clang.yml index 7dea031..d5e17a6 100644 --- a/.github/workflows/bvt-clang.yml +++ b/.github/workflows/bvt-clang.yml @@ -26,24 +26,31 @@ jobs: - name: build and run test with clang 15 run: | - cmake -B build-clang-15 -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang++-15 + cmake -B build-clang-15 -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang++-15 -DCMAKE_BUILD_TYPE=Release cmake --build build-clang-15 -j ctest --test-dir build-clang-15 -j - name: build and run test with clang 16 run: | - cmake -B build-clang-16 -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 + cmake -B build-clang-16 -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_BUILD_TYPE=Release cmake --build build-clang-16 -j ctest --test-dir build-clang-16 -j - name: build and run test with clang 17 run: | - cmake -B build-clang-17 -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 + cmake -B build-clang-17 -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_BUILD_TYPE=Release cmake --build build-clang-17 -j ctest --test-dir build-clang-17 -j - name: build and run test with clang 18 run: | - cmake -B build-clang-18 -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 + cmake -B build-clang-18 -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_BUILD_TYPE=Release cmake --build build-clang-18 -j ctest --test-dir build-clang-18 -j + + - name: run benchmarks + run: | + ./build-clang-15/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true + ./build-clang-16/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true + ./build-clang-17/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true + ./build-clang-18/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true diff --git a/.github/workflows/bvt-gcc.yml b/.github/workflows/bvt-gcc.yml index 142dfa6..c78d3c6 100644 --- a/.github/workflows/bvt-gcc.yml +++ b/.github/workflows/bvt-gcc.yml @@ -26,24 +26,31 @@ jobs: - name: build and run test with gcc 11 run: | - cmake -B build-gcc-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 + cmake -B build-gcc-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_BUILD_TYPE=Release cmake --build build-gcc-11 -j ctest --test-dir build-gcc-11 -j - name: build and run test with gcc 12 run: | - cmake -B build-gcc-12 -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 + cmake -B build-gcc-12 -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DCMAKE_BUILD_TYPE=Release cmake --build build-gcc-12 -j ctest --test-dir build-gcc-12 -j - name: build and run test with gcc 13 run: | - cmake -B build-gcc-13 -DCMAKE_C_COMPILER=gcc-13 -DCMAKE_CXX_COMPILER=g++-13 + cmake -B build-gcc-13 -DCMAKE_C_COMPILER=gcc-13 -DCMAKE_CXX_COMPILER=g++-13 -DCMAKE_BUILD_TYPE=Release cmake --build build-gcc-13 -j ctest --test-dir build-gcc-13 -j - name: build and run test with gcc 14 run: | - cmake -B build-gcc-14 -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 + cmake -B build-gcc-14 -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_BUILD_TYPE=Release cmake --build build-gcc-14 -j ctest --test-dir build-gcc-14 -j + + - name: run benchmarks + run: | + ./build-gcc-11/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true + ./build-gcc-12/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true + ./build-gcc-13/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true + ./build-gcc-14/benchmarks/msft_proxy_benchmarks --benchmark_repetitions=10 --benchmark_report_aggregates_only=true diff --git a/.github/workflows/bvt-msvc.yml b/.github/workflows/bvt-msvc.yml index 8c69492..0972dc0 100644 --- a/.github/workflows/bvt-msvc.yml +++ b/.github/workflows/bvt-msvc.yml @@ -13,11 +13,12 @@ jobs: with: ref: ${{ inputs.branch }} - - name: build with cmake + - name: build and run test with MSVC run: | cmake -B build - cmake --build build -j + cmake --build build --config Release -j + ctest --test-dir build -j - - name: run tests + - name: run benchmarks run: | - ctest --test-dir build -j + .\build\benchmarks\Release\msft_proxy_benchmarks.exe --benchmark_repetitions=10 --benchmark_report_aggregates_only=true diff --git a/CMakeLists.txt b/CMakeLists.txt index 89e3b4b..51ced73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,21 +26,7 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/proxyConfigVersion.cmake # build tests if BUILD_TESTING is ON include(CTest) if (BUILD_TESTING) - include(FetchContent) - # The policy uses the download time for timestamp, instead of the timestamp in the archive. This - # allows for proper rebuilds when a projects URL changes. - if(POLICY CMP0135) - cmake_policy(SET CMP0135 NEW) - endif() - FetchContent_Declare( - googletest - URL https://github.com/google/googletest/releases/download/v1.15.2/googletest-1.15.2.tar.gz - ) - - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # For Windows: Prevent overriding the parent project's compiler/linker settings - set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) # Disable GMock - FetchContent_MakeAvailable(googletest) - add_subdirectory(tests) + add_subdirectory(benchmarks) add_subdirectory(samples) endif() diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 0000000..3b500d1 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,31 @@ +project(msft_proxy_benchmarks) + +include(FetchContent) +# The policy uses the download time for timestamp, instead of the timestamp in the archive. This +# allows for proper rebuilds when a projects URL changes. +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif() + +FetchContent_Declare( + benchmark + URL https://github.com/google/benchmark/archive/refs/tags/v1.9.0.tar.gz + URL_HASH SHA256=35a77f46cc782b16fac8d3b107fbfbb37dcd645f7c28eee19f3b8e0758b48994 +) +set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable tests for google benchmark") +set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "Disable google benchmark unit tests") +FetchContent_MakeAvailable(benchmark) + +add_executable(msft_proxy_benchmarks + proxy_invocation_benchmark_context.cpp + proxy_invocation_benchmark.cpp + proxy_management_benchmark.cpp +) +target_include_directories(msft_proxy_benchmarks PRIVATE .) +target_link_libraries(msft_proxy_benchmarks PRIVATE msft_proxy benchmark::benchmark benchmark::benchmark_main) + +if (MSVC) + target_compile_options(msft_proxy_benchmarks PRIVATE /W4) +else() + target_compile_options(msft_proxy_benchmarks PRIVATE -Wall -Wextra -Wpedantic) +endif() diff --git a/benchmarks/proxy_invocation_benchmark.cpp b/benchmarks/proxy_invocation_benchmark.cpp new file mode 100644 index 0000000..29f85a3 --- /dev/null +++ b/benchmarks/proxy_invocation_benchmark.cpp @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include + +#include "proxy_invocation_benchmark_context.h" + +void BM_SmallObjectInvocationViaProxy(benchmark::State& state) { + for (auto _ : state) { + for (auto& p : SmallObjectInvocationProxyTestData) { + int result = p->Fun(); + benchmark::DoNotOptimize(result); + } + } +} + +void BM_SmallObjectInvocationViaVirtualFunction(benchmark::State& state) { + for (auto _ : state) { + for (auto& p : SmallObjectInvocationVirtualFunctionTestData) { + int result = p->Fun(); + benchmark::DoNotOptimize(result); + } + } +} + +void BM_LargeObjectInvocationViaProxy(benchmark::State& state) { + for (auto _ : state) { + for (auto& p : LargeObjectInvocationProxyTestData) { + int result = p->Fun(); + benchmark::DoNotOptimize(result); + } + } +} + +void BM_LargeObjectInvocationViaVirtualFunction(benchmark::State& state) { + for (auto _ : state) { + for (auto& p : LargeObjectInvocationVirtualFunctionTestData) { + int result = p->Fun(); + benchmark::DoNotOptimize(result); + } + } +} + +BENCHMARK(BM_SmallObjectInvocationViaProxy); +BENCHMARK(BM_SmallObjectInvocationViaVirtualFunction); +BENCHMARK(BM_LargeObjectInvocationViaProxy); +BENCHMARK(BM_LargeObjectInvocationViaVirtualFunction); diff --git a/benchmarks/proxy_invocation_benchmark_context.cpp b/benchmarks/proxy_invocation_benchmark_context.cpp new file mode 100644 index 0000000..00cdcac --- /dev/null +++ b/benchmarks/proxy_invocation_benchmark_context.cpp @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "proxy_invocation_benchmark_context.h" + +namespace { + +constexpr int TestDataSize = 1000000; +constexpr int TypeSeriesCount = 100; + +template +class NonIntrusiveSmallImpl { + public: + explicit NonIntrusiveSmallImpl(int seed) noexcept : seed_(seed) {} + NonIntrusiveSmallImpl(const NonIntrusiveSmallImpl&) noexcept = default; + int Fun() const noexcept { return seed_ ^ (TypeSeries + 1); } + + private: + int seed_; +}; + +template +class NonIntrusiveLargeImpl { + public: + explicit NonIntrusiveLargeImpl(int seed) noexcept : seed_(seed) {} + NonIntrusiveLargeImpl(const NonIntrusiveLargeImpl&) noexcept = default; + int Fun() const noexcept { return seed_ ^ (TypeSeries + 1); } + + private: + void* padding_[16]{}; + int seed_; +}; + +template +class IntrusiveSmallImpl : public InvocationTestBase { + public: + explicit IntrusiveSmallImpl(int seed) noexcept : seed_(seed) {} + IntrusiveSmallImpl(const IntrusiveSmallImpl&) noexcept = default; + int Fun() const noexcept override { return seed_ ^ (TypeSeries + 1); } + + private: + int seed_; +}; + +template +class IntrusiveLargeImpl : public InvocationTestBase { + public: + explicit IntrusiveLargeImpl(int seed) noexcept : seed_(seed) {} + IntrusiveLargeImpl(const IntrusiveLargeImpl&) noexcept = default; + int Fun() const noexcept override { return seed_ ^ (TypeSeries + 1); } + + private: + void* padding_[16]{}; + int seed_; +}; + +template