From 51001056185769d7fa97e9e49eb8b2cf3cb85a0f Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Wed, 2 Oct 2024 15:37:24 +0800 Subject: [PATCH] Add benchmarks --- .github/workflows/bvt-appleclang.yml | 6 +- .github/workflows/bvt-clang.yml | 15 ++-- .github/workflows/bvt-gcc.yml | 16 +++-- .github/workflows/bvt-msvc.yml | 9 +-- CMakeLists.txt | 16 +---- benchmarks/CMakeLists.txt | 30 ++++++++ ...roxy_small_object_invocation_benchmark.cpp | 27 ++++++++ ...ll_object_invocation_benchmark_context.cpp | 68 +++++++++++++++++++ ...mall_object_invocation_benchmark_context.h | 21 ++++++ tests/CMakeLists.txt | 21 +++++- 10 files changed, 199 insertions(+), 30 deletions(-) create mode 100644 benchmarks/CMakeLists.txt create mode 100644 benchmarks/proxy_small_object_invocation_benchmark.cpp create mode 100644 benchmarks/proxy_small_object_invocation_benchmark_context.cpp create mode 100644 benchmarks/proxy_small_object_invocation_benchmark_context.h diff --git a/.github/workflows/bvt-appleclang.yml b/.github/workflows/bvt-appleclang.yml index 2aebf90..d615bc3 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 diff --git a/.github/workflows/bvt-clang.yml b/.github/workflows/bvt-clang.yml index 7dea031..e8098a4 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 + ./build-clang-16/benchmarks/msft_proxy_benchmarks + ./build-clang-17/benchmarks/msft_proxy_benchmarks + ./build-clang-18/benchmarks/msft_proxy_benchmarks diff --git a/.github/workflows/bvt-gcc.yml b/.github/workflows/bvt-gcc.yml index 142dfa6..6e12b12 100644 --- a/.github/workflows/bvt-gcc.yml +++ b/.github/workflows/bvt-gcc.yml @@ -7,6 +7,7 @@ on: jobs: bvt-gcc: + runs-on: ubuntu-24.04 runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 @@ -26,24 +27,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 + ./build-gcc-12/benchmarks/msft_proxy_benchmarks + ./build-gcc-13/benchmarks/msft_proxy_benchmarks + ./build-gcc-14/benchmarks/msft_proxy_benchmarks diff --git a/.github/workflows/bvt-msvc.yml b/.github/workflows/bvt-msvc.yml index 8c69492..3898f78 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 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..7d96945 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,30 @@ +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_small_object_invocation_benchmark_context.cpp + proxy_small_object_invocation_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_small_object_invocation_benchmark.cpp b/benchmarks/proxy_small_object_invocation_benchmark.cpp new file mode 100644 index 0000000..d97a9ee --- /dev/null +++ b/benchmarks/proxy_small_object_invocation_benchmark.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include + +#include "proxy_small_object_invocation_benchmark_context.h" + +void BM_SmallObjectInvocationViaProxy(benchmark::State& state) { + for (auto _ : state) { + for (auto& p : ProxyTestData) { + int result = p->Fun(); + benchmark::DoNotOptimize(result); + } + } +} + +void BM_SmallObjectInvocationViaVirtualFunction(benchmark::State& state) { + for (auto _ : state) { + for (auto& p : VirtualFunctionTestData) { + int result = p->Fun(); + benchmark::DoNotOptimize(result); + } + } +} + +BENCHMARK(BM_SmallObjectInvocationViaProxy); +BENCHMARK(BM_SmallObjectInvocationViaVirtualFunction); diff --git a/benchmarks/proxy_small_object_invocation_benchmark_context.cpp b/benchmarks/proxy_small_object_invocation_benchmark_context.cpp new file mode 100644 index 0000000..6bb48a8 --- /dev/null +++ b/benchmarks/proxy_small_object_invocation_benchmark_context.cpp @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "proxy_small_object_invocation_benchmark_context.h" + +namespace { + +constexpr std::size_t TestDataSize = 1500000; +constexpr std::size_t TypeSeriesCount = 3; + +template +class NonIntrusiveImpl { + public: + explicit NonIntrusiveImpl(int seed) noexcept : seed_(seed) {} + NonIntrusiveImpl(const NonIntrusiveImpl&) noexcept = default; + int Fun() const noexcept { return seed_ ^ (TypeSeries + 1u); } + + private: + int seed_; +}; + +template +class IntrusiveImpl : public TestBase { + public: + explicit IntrusiveImpl(int seed) noexcept : seed_(seed) {} + IntrusiveImpl(const IntrusiveImpl&) noexcept = default; + int Fun() const noexcept override { return seed_ ^ (TypeSeries + 1u); } + + private: + int seed_; +}; + +template +void FillProxyTestData(std::vector>& data) { + if constexpr (FromTypeSeries < TypeSeriesCount) { + for (std::size_t i = FromTypeSeries; i < data.size(); i += TypeSeriesCount) { + data[i] = pro::make_proxy>(static_cast(i)); + } + FillProxyTestData(data); + } +} + +std::vector> GenerateProxyTestData() { + std::vector> result(TestDataSize); + FillProxyTestData<0u>(result); + return result; +} + +template +void FillVirtualFunctionTestData(std::vector>& data) { + if constexpr (FromTypeSeries < TypeSeriesCount) { + for (std::size_t i = FromTypeSeries; i < data.size(); i += TypeSeriesCount) { + data[i].reset(new IntrusiveImpl(static_cast(i))); + } + FillVirtualFunctionTestData(data); + } +} + +std::vector> GenerateVirtualFunctionTestData() { + std::vector> result(TestDataSize); + FillVirtualFunctionTestData<0u>(result); + return result; +} + +} // namespace + +const std::vector> ProxyTestData = GenerateProxyTestData(); +const std::vector> VirtualFunctionTestData = GenerateVirtualFunctionTestData(); diff --git a/benchmarks/proxy_small_object_invocation_benchmark_context.h b/benchmarks/proxy_small_object_invocation_benchmark_context.h new file mode 100644 index 0000000..4c6c7e3 --- /dev/null +++ b/benchmarks/proxy_small_object_invocation_benchmark_context.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include + +#include "proxy.h" + +PRO_DEF_MEM_DISPATCH(MemFun, Fun); + +struct TestFacade : pro::facade_builder + ::add_convention + ::build{}; + +struct TestBase { + virtual int Fun() const = 0; + virtual ~TestBase() = default; +}; + +extern const std::vector> ProxyTestData; +extern const std::vector> VirtualFunctionTestData; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 49fa868..8d91ed1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,21 @@ project(msft_proxy_tests) + +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 + URL_HASH SHA256=7b42b4d6ed48810c5362c265a17faebe90dc2373c885e5216439d37927f02926 +) +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_executable(msft_proxy_tests proxy_creation_tests.cpp proxy_dispatch_tests.cpp @@ -13,9 +30,9 @@ target_link_libraries(msft_proxy_tests PRIVATE msft_proxy) target_link_libraries(msft_proxy_tests PRIVATE gtest_main) if (MSVC) - target_compile_options(msft_proxy_tests PRIVATE /W4 /WX) + target_compile_options(msft_proxy_tests PRIVATE /W4) else() - target_compile_options(msft_proxy_tests PRIVATE -Wall -Wextra -Wpedantic -Werror) + target_compile_options(msft_proxy_tests PRIVATE -Wall -Wextra -Wpedantic) endif() include(GoogleTest)