diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml new file mode 100644 index 000000000..55bd15147 --- /dev/null +++ b/.github/workflows/bench.yml @@ -0,0 +1,44 @@ +name: bench-linux + +on: + pull_request: + push: + +permissions: + deployments: write + contents: write + +jobs: + bench_thyme_ubuntu: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + submodules: "recursive" + + - name: Install dependencies + run: | + sudo apt-get update && sudo apt-get install -y libgtk-3-dev ninja-build libwxgtk3.0-gtk3-dev libsdl2-dev libavcodec-dev libavformat-dev + + - name: Configure Thyme + run: | + cmake -DSTANDALONE=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_BENCHMARKS=ON -B build -G Ninja + + - name: Build Thyme + run: | + cmake --build build + + - name: Bench Thyme + run: | + cd build + ./thyme_benchmarks --benchmark_format=json | tee benchmark_result.json + + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@v1 + with: + name: Thyme Benchmarks + tool: 'googlecpp' + output-file-path: build/benchmark_result.json + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true diff --git a/CMakeLists.txt b/CMakeLists.txt index 20408a1c4..215d0e59e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,9 +96,10 @@ option(USE_SDL2 "Use SDL2 for crossplatform window handling." ${DEFAULT_SDL2}) option(LOGGING "Enable debug logging." ${DEFAULT_LOGGING}) option(ASSERTIONS "Enable debug assertions." ${DEFAULT_ASSERTIONS}) option(USE_CRASHPAD "Enable the use of the Crashpad library for crash handling and reporting." OFF) -option(BUILD_TESTS "Builds the unit tests." OFF) option(USE_SANITIZER "Builds with address sanitizer" OFF) +option(BUILD_TESTS "Builds the unit tests." OFF) option(BUILD_COVERAGE "Instruments the code with coverage." OFF) +option(BUILD_BENCHMARKS "Builds the benchmarks." OFF) option(BUILD_TOOLS "Builds the developer/debug tools." OFF) include(CMakeDependentOption) @@ -416,7 +417,23 @@ if(DLL_INSTALL_PREFIX AND ${CMAKE_VERSION} VERSION_GREATER "3.13.0") endif() # Build tests +if(BUILD_TESTS OR BUILD_BENCHMARKS) + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.12.1 + ) + + FetchContent_MakeAvailable(googletest) +endif() + if(BUILD_TESTS) enable_testing() add_subdirectory(tests) endif() + +# Build benchmarks +if(BUILD_BENCHMARKS) + add_subdirectory(bench) +endif() + diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt new file mode 100644 index 000000000..51792dc34 --- /dev/null +++ b/bench/CMakeLists.txt @@ -0,0 +1,23 @@ +FetchContent_Declare( + benchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG v1.7.1 +) + +FetchContent_MakeAvailable(benchmark) + +set(BENCH_SRCS + bench_refpack.cpp + bench_gamemath_cm.cpp + bench_gamemath_gm.cpp +) + +add_executable(thyme_benchmarks ${BENCH_SRCS}) +target_link_libraries(thyme_benchmarks benchmark::benchmark benchmark::benchmark_main) +target_compile_definitions(thyme_benchmarks PRIVATE) + +if(STANDALONE) + target_link_libraries(thyme_benchmarks thyme_lib) +else() + target_link_libraries(thyme_benchmarks thyme_dll) +endif() diff --git a/bench/bench_gamemath_cm.cpp b/bench/bench_gamemath_cm.cpp new file mode 100644 index 000000000..011fa7fc1 --- /dev/null +++ b/bench/bench_gamemath_cm.cpp @@ -0,0 +1,98 @@ +#include +#include + +#undef BUILD_WITH_GAMEMATH +#include "gamemath.h" + +static void GameMath_CM_Fast_To_Int_Floor(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + float v = std::rand() / 100.0f; + state.ResumeTiming(); + GameMath::Fast_To_Int_Floor(v); + } +} + +static void GameMath_CM_Fast_To_Int_Ceil(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + float v = std::rand() / 100.0f; + state.ResumeTiming(); + GameMath::Fast_To_Int_Ceil(v); + } +} + +static void GameMath_CM_Fast_To_Int_Truncate(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + float v = std::rand() / 100.0f; + state.ResumeTiming(); + GameMath::Fast_To_Int_Truncate(v); + } +} + +static void GameMath_CM_Floor(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Floor(v); + } +} + +static void GameMath_CM_Ceil(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Ceil(v); + } +} + +static void GameMath_CM_Cos(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Cos(v); + } +} + +static void GameMath_CM_Sin(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Sin(v); + } +} + +// Register the function as a benchmark +BENCHMARK(GameMath_CM_Fast_To_Int_Floor); +BENCHMARK(GameMath_CM_Fast_To_Int_Ceil); +BENCHMARK(GameMath_CM_Fast_To_Int_Truncate); +BENCHMARK(GameMath_CM_Floor); +BENCHMARK(GameMath_CM_Ceil); +BENCHMARK(GameMath_CM_Cos); +BENCHMARK(GameMath_CM_Sin); diff --git a/bench/bench_gamemath_gm.cpp b/bench/bench_gamemath_gm.cpp new file mode 100644 index 000000000..3cae5e857 --- /dev/null +++ b/bench/bench_gamemath_gm.cpp @@ -0,0 +1,105 @@ +#include +#include + +#ifndef BUILD_WITH_GAMEMATH +#define BUILD_WITH_GAMEMATH +#else +#define HAS_GAMEMATH_IMPL +#endif +#include "gamemath.h" + +static void GameMath_GM_Fast_To_Int_Floor(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + float v = std::rand() / 100.0f; + state.ResumeTiming(); + GameMath::Fast_To_Int_Floor(v); + } +} + +static void GameMath_GM_Fast_To_Int_Ceil(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + float v = std::rand() / 100.0f; + state.ResumeTiming(); + GameMath::Fast_To_Int_Ceil(v); + } +} + +static void GameMath_GM_Fast_To_Int_Truncate(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + float v = std::rand() / 100.0f; + state.ResumeTiming(); + GameMath::Fast_To_Int_Truncate(v); + } +} + +static void GameMath_GM_Floor(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Floor(v); + } +} + +static void GameMath_GM_Ceil(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Ceil(v); + } +} + +// Register the function as a benchmark +BENCHMARK(GameMath_GM_Fast_To_Int_Floor); +BENCHMARK(GameMath_GM_Fast_To_Int_Ceil); +BENCHMARK(GameMath_GM_Fast_To_Int_Truncate); +BENCHMARK(GameMath_GM_Floor); +BENCHMARK(GameMath_GM_Ceil); + +#ifdef HAS_GAMEMATH_IMPL +static void GameMath_GM_Cos(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Cos(v); + } +} + +static void GameMath_GM_Sin(benchmark::State &state) +{ + GameMath::Init(); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + char v = std::rand() & 0xFF; + state.ResumeTiming(); + GameMath::Sin(v); + } +} + +BENCHMARK(GameMath_GM_Cos); +BENCHMARK(GameMath_GM_Sin); +#endif diff --git a/bench/bench_refpack.cpp b/bench/bench_refpack.cpp new file mode 100644 index 000000000..2e390a1c0 --- /dev/null +++ b/bench/bench_refpack.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "refpack.h" + +static void RefPack_Compress(benchmark::State &state) +{ + std::vector src(0XFFFF0); + std::vector dst(0XFFFF0 * 2); + for (auto _ : state) { + state.PauseTiming(); + std::srand(unsigned(std::time(nullptr))); + std::generate(src.begin(), src.end(), std::rand); + state.ResumeTiming(); + + RefPack_Compress(dst.data(), src.data(), src.size(), nullptr); + } + + state.SetBytesProcessed(state.iterations() * src.size()); +} + +static void RefPack_Uncompress(benchmark::State &state) +{ + std::vector src(0XFFFF0); + std::vector dst(0XFFFF0 * 2); + + std::srand(unsigned(std::time(nullptr))); + std::generate(src.begin(), src.end(), std::rand); + int compressed_size = RefPack_Compress(dst.data(), src.data(), src.size(), nullptr); + + for (auto _ : state) { + RefPack_Uncompress(src.data(), dst.data(), nullptr); + } + + state.SetBytesProcessed(state.iterations() * compressed_size); +} + +// Register the function as a benchmark +BENCHMARK(RefPack_Compress); +BENCHMARK(RefPack_Uncompress); \ No newline at end of file diff --git a/src/w3d/math/gamemath.h b/src/w3d/math/gamemath.h index fef2fc912..40ce977f7 100644 --- a/src/w3d/math/gamemath.h +++ b/src/w3d/math/gamemath.h @@ -68,10 +68,17 @@ extern const Array _FastInvSinTable; inline float Normalize_Angle(float angle) { +#ifdef BUILD_WITH_GAMEMATH captainslog_dbgassert(!gm_isnanf(angle), "Angle is NAN in normalizeAngle!\n"); if (gm_isnanf(angle)) { return 0.0f; } +#else + captainslog_dbgassert(!isnanf(angle), "Angle is NAN in normalizeAngle!\n"); + if (isnanf(angle)) { + return 0.0f; + } +#endif while (angle > GAMEMATH_PI) { angle = angle - GAMEMATH_PI * 2; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2b24a1bfd..aaf707a94 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,11 +1,3 @@ -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.1 -) - -FetchContent_MakeAvailable(googletest) - set(TEST_SRCS main.cpp globals.cpp