From ca4544f04cc67c296e58170e76203bc11519d988 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Oct 2023 10:35:06 +0200 Subject: add benchmark executable --- .github/workflows/cmake-tag.yml | 3 +- .github/workflows/cmake.yml | 3 +- .gitmodules | 3 ++ CMakeLists.txt | 36 ++++++++++++++-------- bench/00-noop.cpp | 15 +++++++++ bench/01-dijkstra.cpp | 67 +++++++++++++++++++++++++++++++++++++++++ bench/CMakeLists.txt | 24 +++++++++++++++ bench/dummy.cc | 0 bench/main.cpp | 57 +++++++++++++++++++++++++++++++++++ compat/headless.hpp | 12 ++++++++ external/CMakeLists.txt | 34 ++++++++++++++++++++- external/benchmark | 1 + src/path-search-dijkstra.cpp | 2 +- src/path-search-result.cpp | 2 ++ src/path-search-result.hpp | 11 +++---- test/CMakeLists.txt | 15 ++++----- test/app.cpp | 58 ----------------------------------- test/app.hpp | 13 +------- test/dijkstra.cpp | 56 ---------------------------------- test/main.cpp | 55 +++++++++++++++++++++++++++++++++ 20 files changed, 310 insertions(+), 157 deletions(-) create mode 100644 bench/00-noop.cpp create mode 100644 bench/01-dijkstra.cpp create mode 100644 bench/CMakeLists.txt create mode 100644 bench/dummy.cc create mode 100644 bench/main.cpp create mode 100644 compat/headless.hpp create mode 160000 external/benchmark delete mode 100644 test/app.cpp create mode 100644 test/main.cpp diff --git a/.github/workflows/cmake-tag.yml b/.github/workflows/cmake-tag.yml index 231241c0..811a4926 100644 --- a/.github/workflows/cmake-tag.yml +++ b/.github/workflows/cmake-tag.yml @@ -37,7 +37,7 @@ jobs: - name: Install Linux dependencies run: | sudo apt -q=2 update - sudo apt install g++-12 gdb ninja-build + sudo apt install g++-12 gdb ninja-build libbenchmark-dev sudo apt -q install libgl1-mesa-dri libgl-dev libglx-dev xorg-dev xvfb libopencv-dev sudo apt -q install libsdl2-dev if: matrix.os == 'ubuntu-22.04' @@ -58,6 +58,7 @@ jobs: cd ${{github.workspace}}/build/install export LD_LIBRARY_PATH="$PWD/lib" ASAN_OPTIONS="detect_leaks=0:abort_on_error=1" xvfb-run gdb -q -batch -x ../../.github/gdbscript.py --args bin/floormat-test + +#if 0 +namespace { + +void noop(benchmark::State& state) +{ + for (auto _ : state) + (void)0; +} + +BENCHMARK(noop); + +} // namespace +#endif diff --git a/bench/01-dijkstra.cpp b/bench/01-dijkstra.cpp new file mode 100644 index 00000000..b358f1f9 --- /dev/null +++ b/bench/01-dijkstra.cpp @@ -0,0 +1,67 @@ +#include "src/path-search.hpp" +#include "src/path-search-result.hpp" +#include "loader/loader.hpp" +#include +#include +#include + +namespace floormat { + +namespace { + +auto A = astar(); +bool first_run = true; + +void Dijkstra(benchmark::State& state) +{ + auto w = world(); + + constexpr auto wcx = 1, wcy = 1, wtx = 8, wty = 8, wox = 3, woy = 3; + constexpr auto max_dist = (uint32_t)(Vector2i(Math::abs(wcx)+1, Math::abs(wcy)+1)*TILE_MAX_DIM*iTILE_SIZE2).length(); + constexpr auto wch = chunk_coords_{wcx, wcy, 0}; + constexpr auto wt = local_coords{wtx, wty}; + constexpr auto wpos = global_coords{wch, wt}; + + auto& ch = w[chunk_coords_{0,0,0}]; + auto& ch2 = w[wch]; + auto metal2 = tile_image_proto{loader.tile_atlas("metal2", {2, 2}, pass_mode::blocked), 0}; + + for (int16_t j = wcy - 1; j <= wcy + 1; j++) + for (int16_t i = wcx - 1; i <= wcx + 1; i++) + { + auto &c = w[chunk_coords_{i, j, 0}]; + for (int k : { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, }) + { + c[{ k, k }].wall_north() = metal2; + c[{ k, k }].wall_west() = metal2; + } + } + + ch2[{ wtx, wty }].wall_west() = metal2; + ch2[{ wtx, wty }].wall_north() = metal2; + ch2[{ wtx+1, wty }].wall_west() = metal2; + ch2[{ wtx, wty -1}].wall_north() = metal2; + + fm_assert(ch.is_passability_modified()); + ch.ensure_passability(); + ch2.ensure_passability(); + + auto run = [&] { + A.Dijkstra(w, + {{0,0,0}, {11,9}}, // from + {wpos, {wox, woy}}, // to + 0, max_dist, {32,32}, // size + first_run ? 1 : 0); + }; + + run(); + first_run = false; + for (auto _ : state) + run(); +} + +} // namespace + +BENCHMARK(Dijkstra); + +} // namespace floormat diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt new file mode 100644 index 00000000..ecce9dee --- /dev/null +++ b/bench/CMakeLists.txt @@ -0,0 +1,24 @@ +set(self floormat-benchmark) + +file(GLOB sources "*.cpp" CONFIGURE_ARGS) + +add_library(${self}_o OBJECT "${res}" "${sources}") +add_executable(${self} dummy.cc) + +target_link_libraries(${self}_o PUBLIC + ${floormat_headless-library} + Magnum::Magnum + Magnum::Trade + nlohmann_json::nlohmann_json + fmt::fmt + tsl::robin_map +) + +if(TARGET benchmark::benchmark) + target_link_libraries(${self}_o PUBLIC benchmark::benchmark) +else() + target_link_libraries(${self}_o PUBLIC benchmark) +endif() + +target_link_libraries(${self} PUBLIC ${self}_o floormat-serialize floormat-draw floormat) +install(TARGETS ${self} RUNTIME DESTINATION bin) diff --git a/bench/dummy.cc b/bench/dummy.cc new file mode 100644 index 00000000..e69de29b diff --git a/bench/main.cpp b/bench/main.cpp new file mode 100644 index 00000000..80a491ec --- /dev/null +++ b/bench/main.cpp @@ -0,0 +1,57 @@ +#include "loader/loader.hpp" +#include "compat/headless.hpp" +#include + +namespace floormat { + +namespace { + +#define main bench_main +int bench_main(int argc, char** argv); +BENCHMARK_MAIN(); +#undef main + +struct bench_app final : private FM_APPLICATION +{ + using Application = FM_APPLICATION; + explicit bench_app(int argc, char** argv); + + int exec() override; + ~bench_app(); + + int argc; + char** argv; +}; +bench_app::~bench_app() { loader_::destroy(); } + +int argc_ = 0; // NOLINT + +bench_app::bench_app(int argc, char** argv) : + Application { + {argc_, nullptr}, + Configuration{} + }, + argc{argc}, argv{argv} +{ +} + +int bench_app::exec() +{ + return bench_main(argc, argv); +} + +} // namespace + +} // namespace floormat + +using namespace floormat; + +int main(int argc, char** argv) +{ + int status; + { auto app = bench_app{argc, argv}; + status = app.exec(); + } + loader_::destroy(); + return status; +} diff --git a/compat/headless.hpp b/compat/headless.hpp new file mode 100644 index 00000000..6cf597bc --- /dev/null +++ b/compat/headless.hpp @@ -0,0 +1,12 @@ +#pragma once + +#ifdef __APPLE__ +#include +#define FM_APPLICATION Platform::WindowlessCglApplication +#elif defined _WIN32 +#include +#define FM_APPLICATION Platform::WindowlessWglApplication +#else +#include +#define FM_APPLICATION Platform::WindowlessGlxApplication +#endif diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 65b79e0d..18913ccc 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -4,12 +4,24 @@ if(NOT DEFINED FLOORMAT_SUBMODULE-SDL2) find_package(SDL2 QUIET) if(SDL2_FOUND) set(FLOORMAT_SUBMODULE-SDL2 OFF CACHE BOOL - "SDL2 as submodule") + "SDL2 as a submodule") endif() endif() set(FLOORMAT_SUBMODULE-SDL2 ON CACHE BOOL "SDL2 as submodule") + +if(NOT DEFINED FLOORMAT_SUBMODULE-BENCHMARK) + find_package(benchmark QUIET) + if(benchmark_FOUND) + set(FLOORMAT_SUBMODULE-BENCHMARK OFF CACHE BOOL + "Benchmark as a submodule") + endif() +endif() + +set(FLOORMAT_SUBMODULE-BENCHMARK ON CACHE BOOL + "Benchmark as a submodule") + set(FLOORMAT_SUBMODULE-DEPENDENCIES ON CACHE BOOL "Use dependencies included in the source directory (needs git submodule update --init).") @@ -234,6 +246,23 @@ if(FLOORMAT_SUBMODULE-DEPENDENCIES) endif() endfunction() + function(fm_add_benchmark) + set(BUILD_SHARED_LIBS 1) + if(WIN32) + set(HAVE_STD_REGEX 1) + endif() + set(BENCHMARK_ENABLE_TESTING OFF) + set(BENCHMARK_ENABLE_EXCEPTIONS ON) + set(BENCHMARK_ENABLE_LTO OFF) + set(BENCHMARK_ENABLE_WERROR OFF) + set(BENCHMARK_FORCE_WERROR OFF) + set(BENCHMARK_ENABLE_INSTALL OFF) + set(BENCHMARK_ENABLE_DOXYGEN OFF) + set(BENCHMARK_INSTALL_DOCS OFF) + set(BENCHMARK_ENABLE_GTEST_TESTS OFF) + add_subdirectory(benchmark ${system}) + endfunction() + function(fm_add_luajit) set(CMAKE_C_STANDARD 11) set(CMAKE_C_EXTENSIONS 1) @@ -256,6 +285,9 @@ if(FLOORMAT_SUBMODULE-DEPENDENCIES) if(MAGNUM_BUILD_TESTS OR CORRADE_BUILD_TESTS AND NOT DEFINED CORRADE_TESTSUITE_TEST_TARGET) sets(STRING CORRADE_TESTSUITE_TEST_TARGET corrade-test) endif() + if(FLOORMAT_SUBMODULE-BENCHMARK) + fm_add_benchmark() + endif() fm_add_sdl2() #fm_add_luajit() if(MSVC) diff --git a/external/benchmark b/external/benchmark new file mode 160000 index 00000000..ca8d0f7b --- /dev/null +++ b/external/benchmark @@ -0,0 +1 @@ +Subproject commit ca8d0f7b613ac915cd6b161ab01b7be449d1e1cd diff --git a/src/path-search-dijkstra.cpp b/src/path-search-dijkstra.cpp index 77c3d8b6..a40d79ad 100644 --- a/src/path-search-dijkstra.cpp +++ b/src/path-search-dijkstra.cpp @@ -198,7 +198,7 @@ path_search_result astar::Dijkstra(world& w, point from_, point to_, object_id o return {}; path_search_result result; - auto& path = result._node->vec; path.clear(); + auto& path = result.path(); path.clear(); indexes[from_] = 0; nodes.push_back({.dist = 0, .coord = from, .offset = from_offset }); diff --git a/src/path-search-result.cpp b/src/path-search-result.cpp index 9e62a30f..26fcd98d 100644 --- a/src/path-search-result.cpp +++ b/src/path-search-result.cpp @@ -69,5 +69,7 @@ auto path_search_result::operator[](size_t index) const -> const pair& fm_debug_assert(index < _node->vec.size()); return data()[index]; } +auto path_search_result::path() -> std::vector& { fm_assert(_node); return _node->vec; } +auto path_search_result::path() const -> const std::vector& { fm_assert(_node); return _node->vec; } } // namespace floormat diff --git a/src/path-search-result.hpp b/src/path-search-result.hpp index 90a4ba3d..92484c63 100644 --- a/src/path-search-result.hpp +++ b/src/path-search-result.hpp @@ -8,8 +8,6 @@ namespace floormat { struct path_search_result final { - friend class path_search; - friend struct astar; friend struct test_app; struct pair { global_coords pos; Vector2 offset; }; @@ -18,14 +16,18 @@ struct path_search_result final const pair& operator[](size_t index) const; size_t size() const; + std::vector& path(); + const std::vector& path() const; explicit operator ArrayView() const; explicit operator bool() const; -private: fm_DECLARE_DEFAULT_MOVE_ASSIGNMENT_(path_search_result); path_search_result(const path_search_result& x) noexcept; path_search_result& operator=(const path_search_result& x) noexcept; + path_search_result(); + ~path_search_result() noexcept; +private: static constexpr size_t min_length = TILE_MAX_DIM*2; struct node @@ -45,9 +47,6 @@ private: static std::unique_ptr _pool; // NOLINT(*-avoid-non-const-global-variables) - path_search_result(); - ~path_search_result() noexcept; - std::unique_ptr _node; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0d713de5..f8048278 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,15 +4,12 @@ file(GLOB sources "*.cpp" CONFIGURE_ARGS) file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/test") add_library(${self}_o OBJECT "${sources}") -target_link_libraries(${self}_o PUBLIC Magnum::GL Magnum::Trade nlohmann_json::nlohmann_json fmt::fmt tsl::robin_map) - -if(APPLE) - target_link_libraries(${self}_o PUBLIC Magnum::WindowlessCglApplication) -elseif(WIN32) - target_link_libraries(${self}_o PUBLIC Magnum::WindowlessWglApplication ntdll) -else() - target_link_libraries(${self}_o PUBLIC Magnum::WindowlessGlxApplication) -endif() +target_link_libraries(${self}_o PUBLIC + ${floormat_headless-library} + Magnum::GL Magnum::Trade + nlohmann_json::nlohmann_json + fmt::fmt tsl::robin_map +) add_executable(${self} dummy.cc) target_link_libraries(${self} ${self}_o floormat-serialize floormat) diff --git a/test/app.cpp b/test/app.cpp deleted file mode 100644 index 3e1f7f82..00000000 --- a/test/app.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "app.hpp" -#include "compat/assert.hpp" -#include "loader/loader.hpp" -#include -#include - -namespace floormat { - -test_app::test_app(const Arguments& arguments): - Application { - arguments, - Configuration{} - } -{ -} - -test_app::~test_app() -{ - loader_::destroy(); -} - -int test_app::exec() -{ - test_coords(); - test_json(); - test_tile_iter(); - test_magnum_math(); - test_entity(); - test_loader(); - test_bitmask(); - test_serializer_1(); - test_serializer_2(); - test_path_search(); - test_math(); - test_hash(); - test_path_search_node_pool(); - - test_dijkstra(); - - zzz_test_misc(); - - return 0; -} - -} // namespace floormat - -int main(int argc, char** argv) -{ -#ifdef _WIN32 - // NOLINTNEXTLINE(concurrency-mt-unsafe) - if (const auto* s = std::getenv("MAGNUM_LOG"); !s || !*s) - _putenv("MAGNUM_LOG=quiet"); -#else - setenv("MAGNUM_LOG", "quiet", 0); -#endif - floormat::test_app application{{argc, argv}}; - return application.exec(); -} diff --git a/test/app.hpp b/test/app.hpp index 0822e68f..630acf02 100644 --- a/test/app.hpp +++ b/test/app.hpp @@ -1,19 +1,9 @@ #pragma once #undef FM_NO_DEBUG #include "compat/assert.hpp" +#include "compat/headless.hpp" #include -#ifdef __APPLE__ -#include -#define FM_APPLICATION Platform::WindowlessCglApplication -#elif defined _WIN32 -#include -#define FM_APPLICATION Platform::WindowlessWglApplication -#else -#include -#define FM_APPLICATION Platform::WindowlessGlxApplication -#endif - namespace floormat { struct chunk_coords; @@ -44,7 +34,6 @@ struct test_app final : private FM_APPLICATION static void test_path_search(); static void test_hash(); static void test_path_search_node_pool(); - static void test_dijkstra(); static void zzz_test_misc(); }; } // namespace floormat diff --git a/test/dijkstra.cpp b/test/dijkstra.cpp index 301257b1..e69de29b 100644 --- a/test/dijkstra.cpp +++ b/test/dijkstra.cpp @@ -1,56 +0,0 @@ -#include "app.hpp" -#include "bench.hpp" -#include "src/path-search.hpp" -#include "loader/loader.hpp" -#include - -namespace floormat { - -void test_app::test_dijkstra() -{ - auto w = world(); - auto a = astar(); - - constexpr auto wcx = 1, wcy = 1, wtx = 8, wty = 8, wox = 3, woy = 3; - constexpr auto max_dist = (uint32_t)(Vector2i(Math::abs(wcx)+1, Math::abs(wcy)+1)*TILE_MAX_DIM*iTILE_SIZE2).length(); - constexpr auto wch = chunk_coords_{wcx, wcy, 0}; - constexpr auto wt = local_coords{wtx, wty}; - constexpr auto wpos = global_coords{wch, wt}; - - auto& ch = w[chunk_coords_{0,0,0}]; -#if 1 - auto& ch2 = w[wch]; - auto metal2 = tile_image_proto{loader.tile_atlas("metal2", {2, 2}, pass_mode::blocked), 0}; - - ch[{4, 4}].wall_west() = metal2; - ch[{4, 4}].wall_north() = metal2; - - ch2[{ wtx, wty }].wall_west() = metal2; - ch2[{ wtx, wty }].wall_north() = metal2; - ch2[{ wtx+1, wty }].wall_west() = metal2; - ch2[{ wtx, wty -1}].wall_north() = metal2; -#endif - - fm_assert(ch.is_passability_modified()); - - auto do_bench = [&](int count, int debug) { - for (int i = 0; i < count; i++) - a.Dijkstra(w, - {{0,0,0}, {11,9}}, // from - {wpos, {wox, woy}}, // to - 0, max_dist, {32,32}, // size - debug); - }; - - static constexpr int iters = 10; - if constexpr (iters > 1) - do_bench(1, 1); -#if 1 - for (int i = 0; i < iters; i++) - bench_run("Dijkstra", [&] { - do_bench(1, iters == 1); - }); -#endif -} - -} // namespace floormat diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 00000000..c6ef7557 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,55 @@ +#include "app.hpp" +#include "compat/assert.hpp" +#include "loader/loader.hpp" +#include +#include + +namespace floormat { + +test_app::test_app(const Arguments& arguments): + Application { + arguments, + Configuration{} + } +{ +} + +test_app::~test_app() +{ + loader_::destroy(); +} + +int test_app::exec() +{ + test_coords(); + test_json(); + test_tile_iter(); + test_magnum_math(); + test_entity(); + test_loader(); + test_bitmask(); + test_serializer_1(); + test_serializer_2(); + test_path_search(); + test_math(); + test_hash(); + test_path_search_node_pool(); + zzz_test_misc(); + + return 0; +} + +} // namespace floormat + +int main(int argc, char** argv) +{ +#ifdef _WIN32 + // NOLINTNEXTLINE(concurrency-mt-unsafe) + if (const auto* s = std::getenv("MAGNUM_LOG"); !s || !*s) + _putenv("MAGNUM_LOG=quiet"); +#else + setenv("MAGNUM_LOG", "quiet", 0); +#endif + floormat::test_app application{{argc, argv}}; + return application.exec(); +} -- cgit v1.2.3