diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c93366d20..c51074eca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -497,3 +497,53 @@ jobs: mpiexec -n 2 ./demos/FiniteVolume/finite-volume-burgers --Tf 0.1 --nfiles 1 --max-level 8 # This test is failing with 3 processes due to a bug in the exchange of subdomain corners # mpiexec -n 3 ./demos/FiniteVolume/finite-volume-burgers --Tf 0.1 --nfiles 1 --max-level 8 + + # + # Benchmarks build and run (separate runner) + # + ######################################################### + linux-benchmarks: + needs: [pre-commit, cppcheck] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Cache + uses: actions/cache@v4 + with: + path: | + ~/.cache/ccache + ~/micromamba-root/envs/samurai-env + key: linux-benchmarks + restore-keys: | + linux-benchmarks + + - name: Mamba and samurai env installation + uses: mamba-org/setup-micromamba@v2 + with: + environment-file: conda/environment.yml + environment-name: samurai-env + cache-environment: true + + - name: Configure (benchmarks only) + shell: bash -l {0} + run: | + cmake \ + . \ + -Bbuild \ + -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_BENCHMARKS=ON \ + -DBUILD_DEMOS=OFF \ + -DBUILD_TESTS=OFF + + - name: Build benchmarks + shell: bash -l {0} + run: | + cmake --build build --target bench_samurai --parallel 2 + + - name: Run bench_samurai (quick sanity) + shell: bash -l {0} + run: | + cd build + ./benchmark/bench_samurai --benchmark_min_time=0.003 --benchmark_color=no --benchmark_format=console diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 8b1886363..7536be8f3 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -22,7 +22,15 @@ find_package(Threads) set(SAMURAI_BENCHMARKS benchmark_celllist_construction.cpp benchmark_search.cpp - benchmark_set.cpp + benchmark_interval.cpp + benchmark_cellarray.cpp + benchmark_level_cell_array.cpp + benchmark_mesh.cpp + benchmark_stencil.cpp + benchmark_field.cpp + benchmark_bc.cpp + benchmark_cell.cpp + benchmark_subset.cpp main.cpp ) diff --git a/benchmark/benchmark_bc.cpp b/benchmark/benchmark_bc.cpp new file mode 100644 index 000000000..22cbc172c --- /dev/null +++ b/benchmark/benchmark_bc.cpp @@ -0,0 +1,91 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////////// +/// utils + +template +auto unitary_box() +{ + using value_t = samurai::default_config::value_t; + using point_t = xt::xtensor_fixed>; + point_t point1; + point_t point2; + if constexpr (dim == 1) + { + point1 = {0}; + point2 = {1}; + } + if constexpr (dim == 2) + { + point1 = {0, 0}; + point2 = {1, 1}; + } + if constexpr (dim == 3) + { + point1 = {0, 0, 0}; + point2 = {1, 1, 1}; + } + + samurai::Box box = samurai::Box(point1, point2); + return box; +} + +// Mesure : Création d'une condition limite sur un maillage uniforme +template +void BC_homogeneous(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig(order)>; // ghost_width = order + auto mesh = samurai::UniformMesh(box, static_cast(state.range(0))); + auto u = samurai::make_vector_field("u", mesh); + + u.fill(1.0); + + // Ajout des compteurs personnalisés + state.counters["Dimension"] = dim; + state.counters["Composantes"] = n_comp; + state.counters["Ordre"] = order; + state.counters["Type BC"] = std::is_same_v> ? 0 : 1; // 0 pour Dirichlet, 1 pour Neumann + + auto& bc_container = u.get_bc(); + + for (auto _ : state) + { + state.PauseTiming(); + bc_container.clear(); + state.ResumeTiming(); + samurai::make_bc(u); + } +} + +// Tests Dirichlet +BENCHMARK_TEMPLATE(BC_homogeneous, 1, 1, samurai::Dirichlet<1>, 1)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 2, 1, samurai::Dirichlet<1>, 1)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 3, 1, samurai::Dirichlet<1>, 1)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 1, 100, samurai::Dirichlet<1>, 1)->DenseRange(1, 1); + +// Tests Neumann +BENCHMARK_TEMPLATE(BC_homogeneous, 1, 1, samurai::Neumann<1>, 1)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 2, 1, samurai::Neumann<1>, 1)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 3, 1, samurai::Neumann<1>, 1)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 1, 100, samurai::Neumann<1>, 1)->DenseRange(1, 1); + +// Tests Dirichlet ordre 3 +BENCHMARK_TEMPLATE(BC_homogeneous, 1, 1, samurai::Dirichlet<3>, 3)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 2, 1, samurai::Dirichlet<3>, 3)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 3, 1, samurai::Dirichlet<3>, 3)->DenseRange(1, 1); +BENCHMARK_TEMPLATE(BC_homogeneous, 1, 100, samurai::Dirichlet<3>, 3)->DenseRange(1, 1); diff --git a/benchmark/benchmark_cell.cpp b/benchmark/benchmark_cell.cpp new file mode 100644 index 000000000..83663bf40 --- /dev/null +++ b/benchmark/benchmark_cell.cpp @@ -0,0 +1,169 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////// +/// utils + +template +auto make_cell() +{ + using value_t = samurai::default_config::value_t; + using point_t = xt::xtensor_fixed>; + + // Initialisation générique des indices et du point de départ + point_t indice = xt::ones({dim}); + point_t begin = xt::zeros({dim}); + + auto indices = xt::xtensor_fixed>(indice); + double scaling_factor = 1.0; + auto c = samurai::Cell>(begin, scaling_factor, 1, indices, 0); + return c; +} + +// Mesure : Construction d'une cellule par défaut +template +void CELL_default(benchmark::State& state) +{ + for (auto _ : state) + { + auto c = samurai::Cell>(); + benchmark::DoNotOptimize(c); + } +} + +// Mesure : Initialisation d'une cellule +template +void CELL_init(benchmark::State& state) +{ + xt::xtensor_fixed> indices; + if constexpr (dim == 1) + { + indices = xt::xtensor_fixed>({1}); + } + else if constexpr (dim == 2) + { + indices = xt::xtensor_fixed>({1, 1}); + } + else if constexpr (dim == 3) + { + indices = xt::xtensor_fixed>({1, 1, 1}); + } + double scaling_factor = 1.0; + for (auto _ : state) + { + if constexpr (dim == 1) + { + auto c = samurai::Cell<1, samurai::Interval>({0}, scaling_factor, 1, indices, 0); + benchmark::DoNotOptimize(c); + } + else if constexpr (dim == 2) + { + auto c = samurai::Cell<2, samurai::Interval>({0, 0}, scaling_factor, 1, indices, 0); + benchmark::DoNotOptimize(c); + } + else if constexpr (dim == 3) + { + auto c = samurai::Cell<3, samurai::Interval>({0, 0, 0}, scaling_factor, 1, indices, 0); + benchmark::DoNotOptimize(c); + } + } +} + +// Mesure : Récupération du centre d'une cellule +template +void CELL_center(benchmark::State& state) +{ + auto c = make_cell(); + for (auto _ : state) + { + auto center = c.center(); + benchmark::DoNotOptimize(center); + } +} + +// Mesure : Récupérayion du centre de la face d'une cellule +template +void CELL_face_center(benchmark::State& state) +{ + auto c = make_cell(); + for (auto _ : state) + { + auto center = c.face_center(); + benchmark::DoNotOptimize(center); + } +} + +// Mesure : Récupération de l'angle d'une cellule +template +void CELL_corner(benchmark::State& state) +{ + auto c = make_cell(); + for (auto _ : state) + { + auto center = c.corner(); + benchmark::DoNotOptimize(center); + } +} + +// Mesure : Test d'égalité entre deux cellules +template +void CELL_equal(benchmark::State& state) +{ + auto c1 = make_cell(); + auto c2 = make_cell(); + for (auto _ : state) + { + auto is_equal = c1 == c2; + benchmark::DoNotOptimize(is_equal); + } +} + +// Mesure : Test d'inégalité entre deux cellules +template +void CELL_different(benchmark::State& state) +{ + auto c1 = make_cell(); + auto c2 = make_cell(); + for (auto _ : state) + { + auto is_equal = c1 != c2; + benchmark::DoNotOptimize(is_equal); + } +} + +BENCHMARK_TEMPLATE(CELL_default, 1); +BENCHMARK_TEMPLATE(CELL_default, 2); +BENCHMARK_TEMPLATE(CELL_default, 3); +BENCHMARK_TEMPLATE(CELL_default, 4); + +BENCHMARK_TEMPLATE(CELL_init, 1); +BENCHMARK_TEMPLATE(CELL_init, 2); +BENCHMARK_TEMPLATE(CELL_init, 3); + +BENCHMARK_TEMPLATE(CELL_center, 1); +BENCHMARK_TEMPLATE(CELL_center, 2); +BENCHMARK_TEMPLATE(CELL_center, 3); + +BENCHMARK_TEMPLATE(CELL_corner, 1); +BENCHMARK_TEMPLATE(CELL_corner, 2); +BENCHMARK_TEMPLATE(CELL_corner, 3); + +BENCHMARK_TEMPLATE(CELL_equal, 1); +BENCHMARK_TEMPLATE(CELL_equal, 2); +BENCHMARK_TEMPLATE(CELL_equal, 3); + +BENCHMARK_TEMPLATE(CELL_different, 1); +BENCHMARK_TEMPLATE(CELL_different, 2); +BENCHMARK_TEMPLATE(CELL_different, 3); diff --git a/benchmark/benchmark_cellarray.cpp b/benchmark/benchmark_cellarray.cpp new file mode 100644 index 000000000..27470a812 --- /dev/null +++ b/benchmark/benchmark_cellarray.cpp @@ -0,0 +1,200 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO : +// Eviter les maillages aléatoires (biais de répétabilité) + +/////////////////////////////////////////////////////////////////// +// utils + +constexpr int DEFAULT_X_INTERVALS = 5; // nombre d'intervalles en X pour les cas 2D/3D + +template +auto gen_regular_intervals = [](int max_index, unsigned int level = 0, int x_intervals = DEFAULT_X_INTERVALS) +{ + samurai::CellList cl; + + int interval_size = 1 << level; // 2^level + int spacing = 1 << (level + 1); // 2^(level+1) + + if constexpr (dim == 1) + { + // En 1D on garde le comportement précédent : un intervalle par abscisse. + for (int x = 0; x < max_index; ++x) + { + int start = x * spacing; + cl[level][{}].add_interval({start, start + interval_size}); + } + } + else if constexpr (dim == 2) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + xt::xtensor_fixed> coord{y}; + cl[level][coord].add_interval({start, end}); + } + } + } + else if constexpr (dim == 3) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + xt::xtensor_fixed> coord{y, z}; + cl[level][coord].add_interval({start, end}); + } + } + } + } + + return cl; +}; + +template +auto cell_array_with_n_intervals(int max_index) +{ + auto cl = gen_regular_intervals(max_index, 0, DEFAULT_X_INTERVALS); + samurai::CellArray ca(cl); + return ca; +} + +////////////////////////////////////////////////////////////////// + +// Mesure : Création d'un CellArray par défaut +template +void CELLARRAY_default(benchmark::State& state) +{ + for (auto _ : state) + { + samurai::CellArray ca = samurai::CellArray(); + } +} + +// Mesure : Création d'un CellArray à partir d'un CellList composé de n intervalles sur une dimension +template +void CELLARRAY_cl_ca_multi(benchmark::State& state) +{ + int max_index = static_cast(state.range(0)); + auto cl = gen_regular_intervals(max_index, 0, DEFAULT_X_INTERVALS); + + // Calculer le nombre d'intervalles selon la nouvelle logique + std::size_t nb_intervals; + if constexpr (dim == 1) + { + nb_intervals = max_index; + } + else if constexpr (dim == 2) + { + nb_intervals = DEFAULT_X_INTERVALS * max_index; + } + else if constexpr (dim == 3) + { + nb_intervals = DEFAULT_X_INTERVALS * max_index * max_index; + } + + for (auto _ : state) + { + samurai::CellArray ca(cl); + benchmark::DoNotOptimize(ca[0]); + } + + // Ajouter les compteurs + state.counters["nb_intervals"] = nb_intervals; + state.counters["ns/interval"] = benchmark::Counter(nb_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + state.counters["dim"] = dim; + + state.SetItemsProcessed(state.iterations() * static_cast(nb_intervals)); +} + +// Mesure : Récupération du niveau bas d'un CellList +template +void CELLARRAY_min_level(benchmark::State& state) +{ + samurai::CellList cl; + + cl[state.range(0)][{}].add_interval({0, 1}); + samurai::CellArray ca(cl); + for (auto _ : state) + { + auto min = ca.min_level(); + benchmark::DoNotOptimize(min); + } +} + +// Mesure : Récupération de l'itérateur begin d'un CellArray +template +void CELLARRAY_begin(benchmark::State& state) +{ + samurai::CellList cl; + for (int level = 0; level <= state.range(0); ++level) + { + cl[level][{}].add_interval({0, 1}); + } + samurai::CellArray ca(cl); + for (auto _ : state) + { + auto begin = ca.begin(); + benchmark::DoNotOptimize(begin); + } +} + +// Mesure : Récupérayion de l'itérateur end d'un CellArray +template +void CELLARRAY_end(benchmark::State& state) +{ + samurai::CellList cl; + for (int level = 0; level <= state.range(0); ++level) + { + cl[level][{}].add_interval({0, 1}); + } + samurai::CellArray ca(cl); + for (auto _ : state) + { + auto end = ca.end(); + benchmark::DoNotOptimize(end); + } +} + +BENCHMARK_TEMPLATE(CELLARRAY_default, 1, 12); +BENCHMARK_TEMPLATE(CELLARRAY_default, 2, 12); +BENCHMARK_TEMPLATE(CELLARRAY_default, 3, 12); + +BENCHMARK_TEMPLATE(CELLARRAY_cl_ca_multi, 1)->RangeMultiplier(8)->Range(1 << 1, 10000); +BENCHMARK_TEMPLATE(CELLARRAY_cl_ca_multi, 2)->RangeMultiplier(4)->Range(1 << 1, 2000); +BENCHMARK_TEMPLATE(CELLARRAY_cl_ca_multi, 3)->RangeMultiplier(2)->Range(1 << 1, 45); + +BENCHMARK_TEMPLATE(CELLARRAY_min_level, 1)->Arg(15); +BENCHMARK_TEMPLATE(CELLARRAY_min_level, 2)->Arg(15); +BENCHMARK_TEMPLATE(CELLARRAY_min_level, 3)->Arg(15); + +BENCHMARK_TEMPLATE(CELLARRAY_begin, 1)->Arg(15); +BENCHMARK_TEMPLATE(CELLARRAY_begin, 2)->Arg(15); +BENCHMARK_TEMPLATE(CELLARRAY_begin, 3)->Arg(15); + +BENCHMARK_TEMPLATE(CELLARRAY_end, 1)->Arg(15); +BENCHMARK_TEMPLATE(CELLARRAY_end, 2)->Arg(15); +BENCHMARK_TEMPLATE(CELLARRAY_end, 3)->Arg(15); diff --git a/benchmark/benchmark_celllist_construction.cpp b/benchmark/benchmark_celllist_construction.cpp index 98de53a3d..136e813eb 100644 --- a/benchmark/benchmark_celllist_construction.cpp +++ b/benchmark/benchmark_celllist_construction.cpp @@ -1,109 +1,188 @@ #include -#include + +#include #include #include -static void BM_CellListConstruction_2D(benchmark::State& state) -{ - constexpr std::size_t dim = 2; +//////////////////////////////////////////////////////////// +/// Générateur d'intervalles réguliers (adapté de benchmark_search.cpp) - std::size_t min_level = 1; - std::size_t max_level = 12; +constexpr int DEFAULT_X_INTERVALS = 5; // nombre d'intervalles en X pour les cas 2D/3D +template +auto gen_regular_intervals = [](int max_index, unsigned int level = 0, int x_intervals = DEFAULT_X_INTERVALS) +{ samurai::CellList cl; - for (auto _ : state) + int interval_size = 1 << level; // 2^level + int spacing = 1 << (level + 1); // 2^(level+1) + + if constexpr (dim == 1) { - for (std::size_t s = 0; s < state.range(0); ++s) + // En 1D on garde le comportement précédent : un intervalle par abscisse. + for (int x = 0; x < max_index; ++x) { - auto level = std::experimental::randint(min_level, max_level); - auto x = std::experimental::randint(0, (100 << level) - 1); - auto y = std::experimental::randint(0, (100 << level) - 1); - - cl[level][{y}].add_point(x); + int start = x * spacing; + cl[level][{}].add_interval({start, start + interval_size}); + } + } + else if constexpr (dim == 2) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + xt::xtensor_fixed> coord{y}; + cl[level][coord].add_interval({start, end}); + } + } + } + else if constexpr (dim == 3) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + xt::xtensor_fixed> coord{y, z}; + cl[level][coord].add_interval({start, end}); + } + } } } -} -BENCHMARK(BM_CellListConstruction_2D)->Range(8, 8 << 18); + return cl; +}; -static void BM_CellListConstruction_3D(benchmark::State& state) +// Ancien générateur simple (1D seulement) +template +auto cell_list_with_n_intervals(int64_t size) { - constexpr std::size_t dim = 3; - - std::size_t min_level = 1; - std::size_t max_level = 12; - samurai::CellList cl; - - for (auto _ : state) + for (int64_t i = 0; i < size; i++) { - for (std::size_t s = 0; s < state.range(0); ++s) - { - auto level = std::experimental::randint(min_level, max_level); - auto x = std::experimental::randint(0, (100 << level) - 1); - auto y = std::experimental::randint(0, (100 << level) - 1); - auto z = std::experimental::randint(0, (100 << level) - 1); - - cl[level][{y, z}].add_point(x); - } + int index = static_cast(i); + cl[0][{}].add_interval({2 * index, 2 * index + 1}); } + return cl; } -BENCHMARK(BM_CellListConstruction_3D)->Range(8, 8 << 18); - -static void BM_CellList2CellArray_2D(benchmark::State& state) +// Générateur avec points individuels (1D seulement) - stride de 2 +template +auto cell_list_with_n_points(int64_t size) { - constexpr std::size_t dim = 2; - - std::size_t min_level = 1; - std::size_t max_level = 12; - samurai::CellList cl; - samurai::CellArray ca; - - for (std::size_t s = 0; s < state.range(0); ++s) + for (int64_t i = 0; i < size; i++) { - auto level = std::experimental::randint(min_level, max_level); - auto x = std::experimental::randint(0, (100 << level) - 1); - auto y = std::experimental::randint(0, (100 << level) - 1); - - cl[level][{y}].add_point(x); + int index = static_cast(i); + cl[0][{}].add_point(2 * index); // stride de 2: 0, 2, 4, 6, etc. } + return cl; +} + +//////////////////////////////////////////////////////////// +/// Fonction utilitaire pour compter les intervalles + +template +std::size_t count_intervals(const samurai::CellList& cl) +{ + std::size_t count = 0; + samurai::CellArray ca(cl); + samurai::for_each_interval(ca, + [&](std::size_t, const auto&, const auto&) + { + count++; + }); + return count; +} + +/////////////////////////////////// +// Mesure : constructeur CellList par défaut +template +void CELLLIST_default(benchmark::State& state) +{ for (auto _ : state) { - ca = {cl}; + samurai::CellList cl; + benchmark::DoNotOptimize(cl); } + + state.counters["dimension"] = static_cast(dim); + state.counters["intervals"] = 0; } -BENCHMARK(BM_CellList2CellArray_2D)->Range(8, 8 << 18); +// Mesure : Construction CellList avec intervalles réguliers (ordre décroissant - begin) + +// Mesure : Construction CellList avec le même intervalle répété (same) -static void BM_CellList2CellArray_3D(benchmark::State& state) +// Mesure : Construction CellList avec intervalles réguliers +template +void CELLLIST_add_interval_begin(benchmark::State& state) { - constexpr std::size_t dim = 3; + int max_index = static_cast(state.range(0)); + // Calculer une seule fois pour les métriques + auto cl_sample = gen_regular_intervals(max_index, 0, DEFAULT_X_INTERVALS); + std::size_t total_intervals = count_intervals(cl_sample); - std::size_t min_level = 1; - std::size_t max_level = 12; + for (auto _ : state) + { + auto cl = gen_regular_intervals(max_index, 0, DEFAULT_X_INTERVALS); + benchmark::DoNotOptimize(cl); + } - samurai::CellList cl; - samurai::CellArray ca; + state.counters["dimension"] = static_cast(dim); + state.counters["intervals"] = static_cast(total_intervals); + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); - for (std::size_t s = 0; s < state.range(0); ++s) - { - auto level = std::experimental::randint(min_level, max_level); - auto x = std::experimental::randint(0, (100 << level) - 1); - auto y = std::experimental::randint(0, (100 << level) - 1); - auto z = std::experimental::randint(0, (100 << level) - 1); + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} - cl[level][{y, z}].add_point(x); - } +// Mesure : Copie de CellList par opérateur d'assignation +template +void CELLLIST_copy_assignment(benchmark::State& state) +{ + int max_index = static_cast(state.range(0)); + auto source_cl = gen_regular_intervals(max_index, 0, DEFAULT_X_INTERVALS); + std::size_t total_intervals = count_intervals(source_cl); for (auto _ : state) { - ca = {cl}; + samurai::CellList copied_cl; + copied_cl = source_cl; + benchmark::DoNotOptimize(copied_cl); } + + state.counters["dimension"] = static_cast(dim); + state.counters["intervals"] = static_cast(total_intervals); + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); } -BENCHMARK(BM_CellList2CellArray_3D)->Range(8, 8 << 18); +//////////////////////////////////////////////////////////// +/// Enregistrement des benchmarks + +// Constructeur par défaut +BENCHMARK_TEMPLATE(CELLLIST_default, 1); +BENCHMARK_TEMPLATE(CELLLIST_default, 2); +BENCHMARK_TEMPLATE(CELLLIST_default, 3); + +// Générateur avec intervalles réguliers (toutes dimensions) - Ajusté pour ~10k intervalles max +BENCHMARK_TEMPLATE(CELLLIST_add_interval_begin, 1)->RangeMultiplier(64)->Range(1 << 1, 10000); +BENCHMARK_TEMPLATE(CELLLIST_add_interval_begin, 2)->RangeMultiplier(8)->Range(1 << 1, 2000); +BENCHMARK_TEMPLATE(CELLLIST_add_interval_begin, 3)->RangeMultiplier(4)->Range(1 << 1, 45); + +BENCHMARK_TEMPLATE(CELLLIST_copy_assignment, 1)->RangeMultiplier(64)->Range(1 << 1, 10000); +BENCHMARK_TEMPLATE(CELLLIST_copy_assignment, 2)->RangeMultiplier(8)->Range(1 << 1, 2000); +BENCHMARK_TEMPLATE(CELLLIST_copy_assignment, 3)->RangeMultiplier(4)->Range(1 << 1, 45); diff --git a/benchmark/benchmark_field.cpp b/benchmark/benchmark_field.cpp new file mode 100644 index 000000000..8f6a50d58 --- /dev/null +++ b/benchmark/benchmark_field.cpp @@ -0,0 +1,457 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// utils +template +auto unitary_box() +{ + using value_t = samurai::default_config::value_t; + using point_t = xt::xtensor_fixed>; + point_t point1; + point_t point2; + if constexpr (dim == 1) + { + point1 = {0}; + point2 = {1}; + } + if constexpr (dim == 2) + { + point1 = {0, 0}; + point2 = {1, 1}; + } + if constexpr (dim == 3) + { + point1 = {0, 0, 0}; + point2 = {1, 1, 1}; + } + + samurai::Box box = samurai::Box(point1, point2); + return box; +} + +/// field creation wrapper +template +auto make_field_wrapper(const std::string& name, mesh_t& mesh) +{ + if constexpr (n_comp == 1) + { + return samurai::make_scalar_field(name, mesh); + } + else + { + return samurai::make_vector_field(name, mesh); + } +} + +// Mesure : Allocation d'un champ d'un maillage uniforme de taille de coté n +template +void FIELD_make_field_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto u = make_field_wrapper("u", mesh); + benchmark::DoNotOptimize(u.array()); + } +} + +// Mesure : Remplissage d'un champ 1D de taille de coté n +template +void FIELD_fill_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + auto u = make_field_wrapper("u", mesh); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + u.fill(1.0); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 1); +} + +// Mesure ; Remplissage d'un champ 1D de taille de coté n ,en utilisant for_each_cell (mesure d'overhead) +template +void FIELD_for_each_cell_fill_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + auto u = make_field_wrapper("u", mesh); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + for_each_cell(mesh, + [&](auto cell) + { + u[cell] = 1.0; + }); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 1); +} + +// Weird : MPI issue ??? wtf ??? +template +void FIELD_equal_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + auto u = make_field_wrapper<1>(std::string("u"), mesh); + auto v = make_field_wrapper<1>(std::string("v"), mesh); + u.fill(1.0); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + v = u; + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(1) + * static_cast(sizeof(double)) * 2); +} + +// Mesure : Ajout d'un scalaire à un champ par broadcasting +template +void FIELD_add_scalar_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + auto u = make_field_wrapper("u", mesh); + u.fill(1.0); + auto v = make_field_wrapper("v", mesh); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + v = u + 2.0; + benchmark::DoNotOptimize(v[0]); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 2); +} + +// Mesure : Ajout d'un scalaire à un champ par "for_each_cell" +template +void FIELD_for_each_cell_add_scalar_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + auto u = make_field_wrapper("u", mesh); + u.fill(1.0); + auto v = make_field_wrapper("v", mesh); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + for_each_cell(mesh, + [&](auto cell) + { + v[cell] = u[cell] + 1.0; + }); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 2); +} + +// Mesure : Somme de deux champs 1D par expression +template +void FIELD_add_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + auto u = make_field_wrapper("u", mesh); + u.fill(1.0); + auto v = make_field_wrapper("v", mesh); + v.fill(1.0); + auto w = make_field_wrapper("w", mesh); + w.fill(0.0); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + w = u + v; + benchmark::DoNotOptimize(w[0]); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 3); +} + +// Mesure : Somme de deux champs 1D par "for_each_cell" +template +void FIELD_for_each_cell_add_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + auto u = make_field_wrapper("u", mesh); + u.fill(1.0); + auto v = make_field_wrapper("v", mesh); + auto w = make_field_wrapper("w", mesh); + w.fill(0.0); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + for_each_cell(mesh, + [&](auto cell) + { + w[cell] = u[cell] + v[cell]; + }); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 3); +} + +// Mesure : Expression complexe avec plusieurs opérations arithmétiques +template +void FIELD_complex_expression_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + + // Création des champs + auto v = make_field_wrapper("v", mesh); + auto w = make_field_wrapper("w", mesh); + auto x = make_field_wrapper("x", mesh); + auto z = make_field_wrapper("z", mesh); + auto u = make_field_wrapper("u", mesh); + + // Initialisation des champs + v.fill(1.0); + w.fill(2.0); + x.fill(3.0); + z.fill(4.0); // z non nul + u.fill(0.0); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + u = 2.0 + v + (w * x) / z; + benchmark::DoNotOptimize(u[0]); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 5); +} + +// Mesure : Expression complexe avec plusieurs opérations arithmétiques (version for_each_cell) +template +void FIELD_for_each_cell_complex_expression_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + auto mesh = samurai::UniformMesh(box, state.range(0)); + + // Création des champs + auto v = make_field_wrapper("v", mesh); + auto w = make_field_wrapper("w", mesh); + auto x = make_field_wrapper("x", mesh); + auto z = make_field_wrapper("z", mesh); + auto u = make_field_wrapper("u", mesh); + + // Initialisation des champs + v.fill(1.0); + w.fill(2.0); + x.fill(3.0); + z.fill(4.0); // z non nul + u.fill(0.0); + + // Ajouter les statistiques + auto total_cells = mesh.nb_cells(); + state.counters["Dimension"] = dim; + state.counters["Mesh_level"] = state.range(0); + state.counters["Total_cells"] = total_cells; + state.counters["Components"] = n_comp; + state.counters["ns/cell"] = benchmark::Counter(total_cells, benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + for_each_cell(mesh, + [&](auto cell) + { + u[cell] = 2.0 + v[cell] + (w[cell] * x[cell]) / z[cell]; + }); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_cells)); + state.SetBytesProcessed(state.iterations() * static_cast(total_cells) * static_cast(n_comp) + * static_cast(sizeof(double)) * 5); +} + +BENCHMARK_TEMPLATE(FIELD_make_field_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_make_field_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_make_field_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_make_field_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_make_field_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_make_field_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_fill_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_fill_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_fill_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_fill_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_fill_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_fill_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_fill_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_fill_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_fill_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_fill_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_fill_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_fill_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_equal_uniform, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_equal_uniform, 2)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_equal_uniform, 3)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_add_scalar_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_add_scalar_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_add_scalar_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_add_scalar_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_add_scalar_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_add_scalar_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_scalar_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_scalar_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_scalar_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_scalar_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_scalar_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_scalar_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_add_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_add_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_add_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_add_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_add_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_add_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_add_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_complex_expression_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_complex_expression_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_complex_expression_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_complex_expression_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_complex_expression_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_complex_expression_uniform, 3, 4)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_complex_expression_uniform, 1, 1)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_complex_expression_uniform, 2, 1)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_complex_expression_uniform, 3, 1)->Arg(5); + +BENCHMARK_TEMPLATE(FIELD_for_each_cell_complex_expression_uniform, 1, 4)->Arg(16); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_complex_expression_uniform, 2, 4)->Arg(8); +BENCHMARK_TEMPLATE(FIELD_for_each_cell_complex_expression_uniform, 3, 4)->Arg(5); diff --git a/benchmark/benchmark_interval.cpp b/benchmark/benchmark_interval.cpp new file mode 100644 index 000000000..2fa429d16 --- /dev/null +++ b/benchmark/benchmark_interval.cpp @@ -0,0 +1,204 @@ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Observation +// - divide is coslty --> verify where and why we use it + +// Mesure : Création d'un intervalle +void INTERVAL_default(benchmark::State& state) +{ + for (auto _ : state) + { + auto interval = samurai::Interval(0, 1, 0); + benchmark::DoNotOptimize(interval); + } +} + +// Mesure : Récupération de la taille d'un intervalle +void INTERVAL_size(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + auto size = interval.size(); + benchmark::DoNotOptimize(size); + } +} + +// Mesure : Test de validité d'un intervalle +void INTERVAL_is_valid(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + auto valid = interval.is_valid(); + benchmark::DoNotOptimize(valid); + } +} + +// Mesure : Test de parité d'un intervalle +void INTERVAL_even_elements(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + auto even = interval.even_elements(); + benchmark::DoNotOptimize(even); + } +} + +// Mesure : Test de parité d'un intervalle +void INTERVAL_odd_elements(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + auto odd = interval.odd_elements(); + benchmark::DoNotOptimize(odd); + } +} + +// Mesure : Multiplication d'un intervalle +void INTERVAL_multiply(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + interval *= 2; + benchmark::DoNotOptimize(interval); + } +} + +// Mesure : divsion d'un intervalle +void INTERVAL_divide(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + interval /= 2; + benchmark::DoNotOptimize(interval); + } +} + +// Here not a redundant test : to be sure that the condition "if start == end" is false. +void INTERVAL_multiply_divide(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + interval *= 2; + interval /= 2; + benchmark::DoNotOptimize(interval); + } +} + +// Mesure : Addition sur un intervalle +void INTERVAL_add(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + interval += 2; + benchmark::DoNotOptimize(interval); + } +} + +// Mesure : Soustraction sur un intervalle +void INTERVAL_sub(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + interval -= 2; + benchmark::DoNotOptimize(interval); + } +} + +// Mesure : Shift sur un intervalle +void INTERVAL_shift_increase(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + interval >>= 2; + benchmark::DoNotOptimize(interval); + } +} + +// Mesure : Shift sur un intervalle +void INTERVAL_shift_decrease(benchmark::State& state) +{ + auto interval = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + interval <<= 2; + benchmark::DoNotOptimize(interval); + } +} + +// Mesure : Test d'egalité d'un intervalle +void INTERVAL_equal(benchmark::State& state) +{ + auto interval1 = samurai::Interval(0, 1, 0); + auto interval2 = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + auto is_equal = interval1 == interval2; + benchmark::DoNotOptimize(is_equal); + } +} + +// Mesure : Test d'inégalité sur un intervalle +void INTERVAL_inequal(benchmark::State& state) +{ + auto interval1 = samurai::Interval(0, 1, 0); + auto interval2 = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + auto is_inequal = interval1 != interval2; + benchmark::DoNotOptimize(is_inequal); + } +} + +// Mesure : Comparaison sur un intervalle +void INTERVAL_less(benchmark::State& state) +{ + auto interval1 = samurai::Interval(0, 1, 0); + auto interval2 = samurai::Interval(0, 1, 0); + for (auto _ : state) + { + auto is_less = interval1 < interval2; + benchmark::DoNotOptimize(is_less); + } +} + +BENCHMARK(INTERVAL_default); +BENCHMARK(INTERVAL_size); +BENCHMARK(INTERVAL_is_valid); +BENCHMARK(INTERVAL_even_elements); +BENCHMARK(INTERVAL_odd_elements); +BENCHMARK(INTERVAL_multiply); +BENCHMARK(INTERVAL_divide); +BENCHMARK(INTERVAL_multiply_divide); + +BENCHMARK(INTERVAL_add); +BENCHMARK(INTERVAL_sub); + +BENCHMARK(INTERVAL_shift_increase); +BENCHMARK(INTERVAL_shift_decrease); + +BENCHMARK(INTERVAL_equal); +BENCHMARK(INTERVAL_inequal); +BENCHMARK(INTERVAL_less); diff --git a/benchmark/benchmark_level_cell_array.cpp b/benchmark/benchmark_level_cell_array.cpp new file mode 100644 index 000000000..1fad07943 --- /dev/null +++ b/benchmark/benchmark_level_cell_array.cpp @@ -0,0 +1,501 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Observation : +// Pourquoi -default est plus lent que _empty_lcl_to_lca en 2D/3D ?? +// max_indices et min_indices très couteux : on peut pas faire mieux ?????? + +constexpr int DEFAULT_X_INTERVALS = 5; // nombre d'intervalles en X pour les cas 2D/3D + +/////////////////////////////////////////////////////////////////// +// utils + +template +auto gen_regular_intervals = [](auto& lcl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + int interval_size = 1 << level; // 2^level + int spacing = 1 << (level + 1); // 2^(level+1) + + if constexpr (dim == 1) + { + // En 1D on garde le comportement précédent : un intervalle par abscisse. + for (int x = 0; x < max_index; ++x) + { + int start = x * spacing; + lcl[{}].add_interval({start, start + interval_size}); + } + } + else if constexpr (dim == 2) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + lcl[{y}].add_interval({start, end}); + } + } + } + else if constexpr (dim == 3) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + lcl[{y, z}].add_interval({start, end}); + } + } + } + } +}; + +template +auto gen_offset_intervals = [](auto& lcl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + int interval_size = 1 << level; // 2^level + int spacing = 1 << (level + 1); // 2^(level+1) + + if constexpr (dim == 1) + { + for (int x = 0; x < max_index; ++x) + { + int start = x * spacing + interval_size; // Décalage pour être disjoint + lcl[{}].add_interval({start, start + interval_size}); + } + } + else if constexpr (dim == 2) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing + interval_size; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + lcl[{y}].add_interval({start, end}); + } + } + } + else if constexpr (dim == 3) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing + interval_size; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + lcl[{y, z}].add_interval({start, end}); + } + } + } + } +}; + +template +auto gen_unique_interval = [](auto& lcl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + int spacing = 1 << (level + 1); // 2^(level+1) + int interval_size = (max_index)*spacing; // Grande taille proportionnelle à max_index + + if constexpr (dim == 1) + { + lcl[{}].add_interval({0, interval_size}); + } + else if constexpr (dim == 2) + { + for (int y = 0; y < max_index; ++y) + { + lcl[{y}].add_interval({0, interval_size}); + } + } + else if constexpr (dim == 3) + { + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + lcl[{y, z}].add_interval({0, interval_size}); + } + } + } +}; + +/////////////////////////////////////////////////////////////////// + +// Mesure : Constructeur par défaut d'un LevelCellArray +template +void LEVELCELLARRAY_default(benchmark::State& state) +{ + using TInterval = samurai::default_config::interval_t; + for (auto _ : state) + { + auto lcl = samurai::LevelCellArray(); + benchmark::DoNotOptimize(lcl); + } +} + +// Mesure : Constructiuon d'un LevelCellArray à partir d'un LevelCellList vide +template +void LEVELCELLARRAY_empty_lcl_to_lca(benchmark::State& state) +{ + using TInterval = samurai::default_config::interval_t; + samurai::LevelCellList lcl; + for (auto _ : state) + { + auto lca = samurai::LevelCellArray(lcl); + benchmark::DoNotOptimize(lca); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +// Mesure : Construction d'un LevelCellArray à partir d'un LevelCellList composé de n intervalles dans une direction +template +void LEVELCELLARRAY_lcl_to_lca(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + + // Créer un LevelCellArray temporaire pour compter les intervalles + auto temp_lca = samurai::LevelCellArray(lcl); + auto total_intervals = temp_lca.nb_intervals(); + + state.counters["Dimension"] = dim; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto lca = samurai::LevelCellArray(lcl); + benchmark::DoNotOptimize(lca); + } +} + +// Mesure : Récupération de l'intérateur begin d'un LevelCellArray +template +void LEVELCELLARRAY_begin(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + for (auto _ : state) + { + auto begin = lca.begin(); + benchmark::DoNotOptimize(begin); + } +} + +// Mesure : Récupération de l'itéateur end d'un LevelCellArray +template +void LEVELCELLARRAY_end(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + for (auto _ : state) + { + auto end = lca.end(); + benchmark::DoNotOptimize(end); + } +} + +// Mesure : Récupération de la taille d'un LevelCellArray +template +void LEVELCELLARRAY_shape(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + for (auto _ : state) + { + auto shape = lca.shape(); + benchmark::DoNotOptimize(shape); + } +} + +// Mesure : Récupération du nombre d'intervalles dans un LevelCellArray +template +void LEVELCELLARRAY_nb_intervals(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + for (auto _ : state) + { + auto nb = lca.nb_intervals(); + benchmark::DoNotOptimize(nb); + } +} + +// Mesure : Récupération du nombre de cellules dans un LevelCellArray +template +void LEVELCELLARRAY_nb_cells(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + auto total_intervals = lca.nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto nb = lca.nb_cells(); + benchmark::DoNotOptimize(nb); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +// Mesure : Récupération de la taille de cellule d'un LevelCellArray +template +void LEVELCELLARRAY_cell_length(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + for (auto _ : state) + { + auto length = lca.cell_length(); + benchmark::DoNotOptimize(length); + } +} + +// Mesure : Récupération du max d'indice d'un LevelCellArray +template +void LEVELCELLARRAY_max_indices(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + auto total_intervals = lca.nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto max = lca.max_indices(); + benchmark::DoNotOptimize(max); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +// Mesure : Récupération du min d'indide d'un LevelCellArray +template +void LEVELCELLARRAY_min_indices(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + auto total_intervals = lca.nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto min = lca.min_indices(); + benchmark::DoNotOptimize(min); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +// Mesure : Récupération du minmax d'indice d'un LevelCellArray +template +void LEVELCELLARRAY_minmax_indices(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + auto total_intervals = lca.nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto minmax = lca.minmax_indices(); + benchmark::DoNotOptimize(minmax); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +// Mesure : Test d'égalité entre deux LevelCellArrays égaux de taille n +template +void LEVELCELLARRAY_equal(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + auto lca2 = samurai::LevelCellArray(lcl); + + auto total_intervals = lca.nb_intervals() + lca2.nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto is_equal = (lca == lca2); + benchmark::DoNotOptimize(is_equal); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +// Mesure : Récupération du niveau bas d'un LevelCellArray +template +void LEVELCELLARRAY_min_level(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + for (auto _ : state) + { + auto min = lca.level(); + benchmark::DoNotOptimize(min); + } +} + +// Mesure : Récupération de l'itérateur reverse begin d'un LevelCellArray +template +void LEVELCELLARRAY_rbegin(benchmark::State& state) +{ + samurai::LevelCellList lcl; + using TInterval = samurai::default_config::interval_t; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(lcl, max_index, 0, DEFAULT_X_INTERVALS); + auto lca = samurai::LevelCellArray(lcl); + + for (auto _ : state) + { + auto rbegin = lca.rbegin(); + benchmark::DoNotOptimize(rbegin); + } +} + +// manque les LevelCellList_iterator +BENCHMARK_TEMPLATE(LEVELCELLARRAY_default, 1); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_default, 2); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_default, 3); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_empty_lcl_to_lca, 1); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_empty_lcl_to_lca, 2); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_empty_lcl_to_lca, 3); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_lcl_to_lca, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_lcl_to_lca, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_lcl_to_lca, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_begin, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_begin, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_begin, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_end, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_end, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_end, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_shape, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_shape, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_shape, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_nb_intervals, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_nb_intervals, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_nb_intervals, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_nb_cells, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_nb_cells, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_nb_cells, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_cell_length, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_cell_length, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_cell_length, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_max_indices, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_max_indices, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_max_indices, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_min_indices, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_min_indices, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_min_indices, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_minmax_indices, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_minmax_indices, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_minmax_indices, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_equal, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_equal, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_equal, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_min_level, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_min_level, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_min_level, 3)->Arg(45); + +BENCHMARK_TEMPLATE(LEVELCELLARRAY_rbegin, 1)->Arg(10000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_rbegin, 2)->Arg(2000); +BENCHMARK_TEMPLATE(LEVELCELLARRAY_rbegin, 3)->Arg(45); diff --git a/benchmark/benchmark_mesh.cpp b/benchmark/benchmark_mesh.cpp new file mode 100644 index 000000000..8f52e79d4 --- /dev/null +++ b/benchmark/benchmark_mesh.cpp @@ -0,0 +1,64 @@ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO : + +///////////////////////////////////////////////////////////////////////////// +/// utils +template +auto unitary_box() +{ + using value_t = samurai::default_config::value_t; + using point_t = xt::xtensor_fixed>; + point_t point1; + point_t point2; + if constexpr (dim == 1) + { + point1 = {0}; + point2 = {1}; + } + if constexpr (dim == 2) + { + point1 = {0, 0}; + point2 = {1, 1}; + } + if constexpr (dim == 3) + { + point1 = {0, 0, 0}; + point2 = {1, 1, 1}; + } + + samurai::Box box = samurai::Box(point1, point2); + return box; +} + +//////////////////////////////////////////////////////////////////////////// + +// Mesure : Création d'une Box uniforme de taille de coté n +template +void MESH_uniform(benchmark::State& state) +{ + samurai::Box box = unitary_box(); + using Config = samurai::UniformConfig; + for (auto _ : state) + { + auto mesh = samurai::UniformMesh(box, state.range(0)); + } +} + +BENCHMARK_TEMPLATE(MESH_uniform, 1)->DenseRange(1, 16); +BENCHMARK_TEMPLATE(MESH_uniform, 2)->DenseRange(1, 14); +BENCHMARK_TEMPLATE(MESH_uniform, 3)->DenseRange(1, 9); diff --git a/benchmark/benchmark_search.cpp b/benchmark/benchmark_search.cpp index 9bb3cbf67..21bedbf58 100644 --- a/benchmark/benchmark_search.cpp +++ b/benchmark/benchmark_search.cpp @@ -1,15 +1,167 @@ -#include #include -#include +#include #include -#include #include #include #include #include +//////////////////////////////////////////////////////////// +/// utils + +constexpr int DEFAULT_X_INTERVALS = 5; // nombre d'intervalles en X pour les cas 2D/3D + +template +auto gen_regular_intervals = [](int max_index, unsigned int level = 0, int x_intervals = DEFAULT_X_INTERVALS) +{ + samurai::CellList cl; + + int interval_size = 1 << level; // 2^level + int spacing = 1 << (level + 1); // 2^(level+1) + + if constexpr (dim == 1) + { + // En 1D on garde le comportement précédent : un intervalle par abscisse. + for (int x = 0; x < max_index; ++x) + { + int start = x * spacing; + cl[level][{}].add_interval({start, start + interval_size}); + } + } + else if constexpr (dim == 2) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + xt::xtensor_fixed> coord{y}; + cl[level][coord].add_interval({start, end}); + } + } + } + else if constexpr (dim == 3) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + xt::xtensor_fixed> coord{y, z}; + cl[level][coord].add_interval({start, end}); + } + } + } + } + + return cl; +}; + +template +auto cell_array_with_n_intervals(int max_index) +{ + auto cl = gen_regular_intervals(max_index, 0, DEFAULT_X_INTERVALS); + samurai::CellArray ca(cl); + return ca; +} + +////////////////////////////////////////////////////////////// + +// Fonction unifiée pour les benchmarks de recherche +template +void FIND_find_unified(benchmark::State& state, const std::function>()>& coord_generator) +{ + auto ca = cell_array_with_n_intervals(state.range(0)); + + // Compter le nombre d'intervalles + std::size_t nb_intervals = 0; + samurai::for_each_interval(ca, + [&](std::size_t level, const auto& interval, const auto& index) + { + nb_intervals++; + }); + + // Compter le nombre d'intervalles dans la direction x + std::size_t nb_intervals_x = state.range(0); + auto coord = coord_generator(); + for (auto _ : state) + { + auto index = find(ca[0], coord); + benchmark::DoNotOptimize(index); + } + + state.counters["nb_intervals"] = nb_intervals; + state.counters["nb_intervals_x"] = nb_intervals_x; + state.counters["dimension"] = dim; + + state.SetItemsProcessed(state.iterations()); +} + +// Fonctions spécialisées pour chaque politique +template +void FIND_find_start(benchmark::State& state) +{ + auto coord_generator = []() + { + xt::xtensor_fixed> coord; + coord.fill(0); + return coord; + }; + FIND_find_unified(state, coord_generator); +} + +template +void FIND_find_end(benchmark::State& state) +{ + auto coord_generator = [&state]() + { + xt::xtensor_fixed> coord; + coord.fill(state.range(0) - 1); + coord[0] = 2 * state.range(0) - 2; + return coord; + }; + FIND_find_unified(state, coord_generator); +} + +template +void FIND_find_middle(benchmark::State& state) +{ + auto coord_generator = [&state]() + { + xt::xtensor_fixed> coord; + // Coordonnées du milieu pour toutes les dimensions sauf x + for (std::size_t i = 1; i < dim; ++i) + { + coord[i] = (state.range(0) - 1) / 2; + } + // Coordonnée x au milieu, mais assurée d'être un multiple de 2 + int middle_x = (2 * state.range(0) - 1) / 2; // Milieu de la plage [0, 2*state.range(0) - 1] + coord[0] = (middle_x / 2) * 2; // S'assurer que c'est un multiple de 2 + return coord; + }; + FIND_find_unified(state, coord_generator); +} + +// Ajusté pour ~10k intervalles max : 1D=10000, 2D=2000, 3D=45 +BENCHMARK_TEMPLATE(FIND_find_start, 1)->Args({2})->Args({32})->Args({1000})->Args({10000}); +BENCHMARK_TEMPLATE(FIND_find_start, 2)->Args({2})->Args({32})->Args({200})->Args({2000}); +BENCHMARK_TEMPLATE(FIND_find_start, 3)->Args({2})->Args({8})->Args({20})->Args({45}); +BENCHMARK_TEMPLATE(FIND_find_end, 1)->Args({2})->Args({32})->Args({1000})->Args({10000}); +BENCHMARK_TEMPLATE(FIND_find_end, 2)->Args({2})->Args({32})->Args({200})->Args({2000}); +BENCHMARK_TEMPLATE(FIND_find_end, 3)->Args({2})->Args({8})->Args({20})->Args({45}); +BENCHMARK_TEMPLATE(FIND_find_middle, 1)->Args({2})->Args({32})->Args({1000})->Args({10000}); +BENCHMARK_TEMPLATE(FIND_find_middle, 2)->Args({2})->Args({32})->Args({200})->Args({2000}); +BENCHMARK_TEMPLATE(FIND_find_middle, 3)->Args({2})->Args({8})->Args({20})->Args({45}); + +/** template auto generate_mesh(int bound, std::size_t start_level, std::size_t max_level) { @@ -26,8 +178,8 @@ auto generate_mesh(int bound, std::size_t start_level, std::size_t max_level) samurai::for_each_interval(ca, [&](std::size_t level, const auto& interval, const auto& index) { - auto choice = xt::random::choice(xt::xtensor_fixed>{true, false}, interval.size()); - for (int i = interval.start, ic = 0; i < interval.end; ++i, ++ic) + auto choice = xt::random::choice(xt::xtensor_fixed>{true, false}, +interval.size()); for (int i = interval.start, ic = 0; i < interval.end; ++i, ++ic) { if (choice[ic]) { @@ -51,6 +203,8 @@ auto generate_mesh(int bound, std::size_t start_level, std::size_t max_level) return ca; } + + template class MyFixture : public ::benchmark::Fixture { @@ -69,11 +223,10 @@ class MyFixture : public ::benchmark::Fixture { std::size_t found = 0; for (auto _ : state) - { - for (std::size_t s = 0; s < state.range(0); ++s) { auto level = std::experimental::randint(min_level, max_level); - std::array coord; +// std::array coord; + xt::xtensor_fixed> coord ; for (auto& c : coord) { c = std::experimental::randint(-bound << level, (bound << level) - 1); @@ -99,6 +252,8 @@ BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, Search_1D, 1, 1000) bench(state); } + + BENCHMARK_REGISTER_F(MyFixture, Search_1D)->DenseRange(1, 10, 1); BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, Search_2D, 2, 10) @@ -116,3 +271,5 @@ BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, Search_3D, 3, 1)(benchmark::State& state) } BENCHMARK_REGISTER_F(MyFixture, Search_3D)->DenseRange(1, 10, 1); + +**/ diff --git a/benchmark/benchmark_set.cpp b/benchmark/benchmark_set.cpp index 0b8af64ab..5e34b71d7 100644 --- a/benchmark/benchmark_set.cpp +++ b/benchmark/benchmark_set.cpp @@ -1,10 +1,10 @@ + #include #include #include #include #include -#include template inline auto init_sets_1(S& set1, S& set2, S& set3) @@ -45,6 +45,7 @@ static void BM_SetCreation(benchmark::State& state) } } +/** static void BM_SetOP(benchmark::State& state) { constexpr std::size_t dim = 2; @@ -57,9 +58,11 @@ static void BM_SetOP(benchmark::State& state) [&](auto& interval, auto&) { interval *= 2; + // error in const }); } } +**/ static void BM_SetCreationWithOn(benchmark::State& state) { @@ -72,6 +75,7 @@ static void BM_SetCreationWithOn(benchmark::State& state) } } +/** static void BM_SetOPWithOn(benchmark::State& state) { constexpr std::size_t dim = 2; @@ -84,10 +88,12 @@ static void BM_SetOPWithOn(benchmark::State& state) [&](auto& interval, auto&) { interval *= 2; + // error in const }); } } - +**/ +/** static void BM_SetOPWithOn2(benchmark::State& state) { constexpr std::size_t dim = 2; @@ -97,16 +103,16 @@ static void BM_SetOPWithOn2(benchmark::State& state) for (auto _ : state) { - auto subset = samurai::intersection(samurai::intersection(set1, samurai::translate(set2, stencil)), samurai::translate(set3, stencil)) - .on(15); - subset( + auto subset = samurai::intersection(samurai::intersection(set1, samurai::translate(set2, stencil)), samurai::translate(set3, +stencil)) .on(15); subset( [&](auto& interval, auto&) { interval *= 2; + // error const }); } } - +**/ static void BM_BigDomain(benchmark::State& state) { constexpr std::size_t dim = 2; @@ -131,8 +137,8 @@ static void BM_BigDomain(benchmark::State& state) } BENCHMARK(BM_SetCreation); -BENCHMARK(BM_SetOP); +// BENCHMARK(BM_SetOP); BENCHMARK(BM_SetCreationWithOn); -BENCHMARK(BM_SetOPWithOn); -BENCHMARK(BM_SetOPWithOn2); +// BENCHMARK(BM_SetOPWithOn); +// BENCHMARK(BM_SetOPWithOn2); BENCHMARK(BM_BigDomain); diff --git a/benchmark/benchmark_stencil.cpp b/benchmark/benchmark_stencil.cpp new file mode 100644 index 000000000..c05f70a0a --- /dev/null +++ b/benchmark/benchmark_stencil.cpp @@ -0,0 +1,41 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// BENCHMARKS - CRÉATION DE STENCILS FONDAMENTAUX +////////////////////////////////////////////////////////////////////////////// + +// Benchmark de création des stencils star (le plus fondamental) +template +void STENCIL_star_creation(benchmark::State& state) +{ + for (auto _ : state) + { + auto stencil = samurai::star_stencil(); + benchmark::DoNotOptimize(stencil); + } +} + +////////////////////////////////////////////////////////////////////////////// +// REGISTRATIONS DES BENCHMARKS +////////////////////////////////////////////////////////////////////////////// + +// Benchmarks Star stencil - configurations essentielles +BENCHMARK_TEMPLATE(STENCIL_star_creation, 2, 1); // 2D, largeur 1 (le plus courant) +BENCHMARK_TEMPLATE(STENCIL_star_creation, 3, 1); // 3D, largeur 1 (le plus courant) +BENCHMARK_TEMPLATE(STENCIL_star_creation, 2, 2); // 2D, largeur 2 +BENCHMARK_TEMPLATE(STENCIL_star_creation, 3, 2); // 3D, largeur 2 diff --git a/benchmark/benchmark_subset.cpp b/benchmark/benchmark_subset.cpp new file mode 100644 index 000000000..a587a6191 --- /dev/null +++ b/benchmark/benchmark_subset.cpp @@ -0,0 +1,656 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Observation : Cela prend environ 10ns par intervalle +// si on compare 2 intervalles de taille n, cela prendra environ 2n * 10ns + +/////////////////////////////////////////////////////////////////// +// Fonctions utilitaires pour la génération d'intervalles +/////////////////////////////////////////////////////////////////// + +constexpr int DEFAULT_X_INTERVALS = 5; // nombre d'intervalles en X pour les cas 2D/3D + +// Générateur « régulier » +template +void gen_regular_intervals(auto& cl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + int interval_size = 1 << level; // 2^level + int spacing = 1 << (level + 1); // 2^(level+1) + + if constexpr (dim == 1) + { + // En 1D on garde le comportement précédent : un intervalle par abscisse. + for (int x = 0; x < max_index; ++x) + { + int start = x * spacing; + cl[level][{}].add_interval({start, start + interval_size}); + } + } + else if constexpr (dim == 2) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + xt::xtensor_fixed> coord{y}; + cl[level][coord].add_interval({start, end}); + } + } + } + else if constexpr (dim == 3) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + xt::xtensor_fixed> coord{y, z}; + cl[level][coord].add_interval({start, end}); + } + } + } + } +} + +// Générateur « décalé » +template +void gen_offset_intervals(auto& cl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + int interval_size = 1 << level; // 2^level + int spacing = 1 << (level + 1); // 2^(level+1) + + if constexpr (dim == 1) + { + for (int x = 0; x < max_index; ++x) + { + int start = x * spacing + interval_size; // Décalage pour être disjoint + cl[level][{}].add_interval({start, start + interval_size}); + } + } + else if constexpr (dim == 2) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing + interval_size; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + xt::xtensor_fixed> coord{y}; + cl[level][coord].add_interval({start, end}); + } + } + } + else if constexpr (dim == 3) + { + int nx = x_intervals; + for (int x = 0; x < nx; ++x) + { + int start = x * spacing + interval_size; + int end = start + interval_size; + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + xt::xtensor_fixed> coord{y, z}; + cl[level][coord].add_interval({start, end}); + } + } + } + } +} + +// Générateur « unique » : un intervalle englobant large +// (utilisé pour les cas « single » dans les benchmarks) +template +void gen_unique_interval(auto& cl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + int spacing = 1 << (level + 1); // 2^(level+1) + int interval_size = (max_index)*spacing; // Grande taille proportionnelle à max_index + + if constexpr (dim == 1) + { + cl[level][{}].add_interval({0, interval_size}); + } + else if constexpr (dim == 2) + { + for (int y = 0; y < max_index; ++y) + { + xt::xtensor_fixed> coord{y}; + cl[level][coord].add_interval({0, interval_size}); + } + } + else if constexpr (dim == 3) + { + for (int y = 0; y < max_index; ++y) + { + for (int z = 0; z < max_index; ++z) + { + xt::xtensor_fixed> coord{y, z}; + cl[level][coord].add_interval({0, interval_size}); + } + } + } +} + +template +auto create_translation_stencil() +{ + xt::xtensor_fixed> stencil; + if constexpr (dim == 1) + { + stencil = xt::xtensor_fixed>({1}); + } + else if constexpr (dim == 2) + { + stencil = xt::xtensor_fixed>({1, 1}); + } + else if constexpr (dim == 3) + { + stencil = xt::xtensor_fixed>({1, 1, 1}); + } + return stencil; +} + +/////////////////////////////////////////////////////////////////// +// Opérations ensemblistes +/////////////////////////////////////////////////////////////////// + +auto op_difference = [](const auto& a, const auto& b) +{ + return samurai::difference(a, b); +}; + +auto op_intersection = [](const auto& a, const auto& b) +{ + return samurai::intersection(a, b); +}; + +auto op_union = [](const auto& a, const auto& b) +{ + return samurai::union_(a, b); +}; + +/////////////////////////////////////////////////////////////////// +// Fonction de benchmark unifiée +/////////////////////////////////////////////////////////////////// + +// Wrappers lambda pour les générateurs afin de permettre la déduction de type +template +auto gen_regular_wrapper = [](auto& cl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + gen_regular_intervals(cl, max_index, level, x_intervals); +}; + +template +auto gen_offset_wrapper = [](auto& cl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + gen_offset_intervals(cl, max_index, level, x_intervals); +}; + +template +auto gen_unique_wrapper = [](auto& cl, int max_index, unsigned int level, int x_intervals = DEFAULT_X_INTERVALS) +{ + gen_unique_interval(cl, max_index, level, x_intervals); +}; + +template +void SUBSET_unified_benchmark_mixed_levels(benchmark::State& state, Gen1&& gen1, Gen2&& gen2, Operation&& operation) +{ + samurai::CellList cl1, cl2; + int max_index = static_cast(state.range(0)); + gen1(cl1, max_index, level1, DEFAULT_X_INTERVALS); + gen2(cl2, max_index, level2, DEFAULT_X_INTERVALS); + samurai::CellArray ca1(cl1); + samurai::CellArray ca2(cl2); + + // Ajouter les statistiques + auto total_intervals = ca1[level1].nb_intervals() + ca2[level2].nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Level1"] = level1; + state.counters["Level2"] = level2; + state.counters["Input1_intervals"] = ca1[level1].nb_intervals(); + state.counters["Input2_intervals"] = ca2[level2].nb_intervals(); + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto total_cells = 0; + auto subset = operation(ca1[level1], ca2[level2]); + subset( + [&total_cells](const auto&, const auto&) + { + total_cells = 1; + }); + benchmark::DoNotOptimize(total_cells); + benchmark::DoNotOptimize(subset); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +/////////////////////////////////////////////////////////////////// +// Fonction de benchmark unifiée pour les opérations imbriquées +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Benchmarks pour les opérations ensemblistes +/////////////////////////////////////////////////////////////////// + +template +void SUBSET_set_diff_identical(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_regular_wrapper, op_difference); +} + +template +void SUBSET_set_diff_disjoint(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_offset_wrapper, op_difference); +} + +template +void SUBSET_set_diff_single(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_unique_wrapper, op_difference); +} + +template +void SUBSET_set_intersect_identical(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_regular_wrapper, op_intersection); +} + +template +void SUBSET_set_intersect_disjoint(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_offset_wrapper, op_intersection); +} + +template +void SUBSET_set_intersect_single(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_unique_wrapper, op_intersection); +} + +template +void SUBSET_set_union_identical(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_regular_wrapper, op_union); +} + +template +void SUBSET_set_union_disjoint(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_offset_wrapper, op_union); +} + +template +void SUBSET_set_union_single(benchmark::State& state) +{ + SUBSET_unified_benchmark_mixed_levels(state, gen_regular_wrapper, gen_unique_wrapper, op_union); +} + +/////////////////////////////////////////////////////////////////// +// Benchmarks pour les opérations géométriques +/////////////////////////////////////////////////////////////////// + +template +void SUBSET_translate(benchmark::State& state) +{ + samurai::CellList cl; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(cl, max_index, level, DEFAULT_X_INTERVALS); + samurai::CellArray ca(cl); + + // Créer le stencil de translation + auto stencil = create_translation_stencil(); + + // Ajouter les statistiques + auto total_intervals = ca[level].nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Level"] = level; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto total_cells = 0; + auto subset = samurai::translate(ca[level], stencil); + subset( + [&total_cells](const auto&, const auto&) + { + total_cells = 1; + }); + benchmark::DoNotOptimize(total_cells); + benchmark::DoNotOptimize(subset); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +template +void SUBSET_translate_and_intersect(benchmark::State& state) +{ + samurai::CellList cl1, cl2; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(cl1, max_index, level1, DEFAULT_X_INTERVALS); + gen_regular_intervals(cl2, max_index, level2, DEFAULT_X_INTERVALS); + samurai::CellArray ca1(cl1); + samurai::CellArray ca2(cl2); + + // Créer le stencil de translation + auto stencil = create_translation_stencil(); + + // Ajouter les statistiques + auto total_intervals = ca1[level1].nb_intervals() + ca2[level2].nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Level1"] = level1; + state.counters["Level2"] = level2; + state.counters["Input1_intervals"] = ca1[level1].nb_intervals(); + state.counters["Input2_intervals"] = ca2[level2].nb_intervals(); + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto total_cells = 0; + // intersection(translate(ca1, stencil), ca2) + auto subset = samurai::intersection(samurai::translate(ca1[level1], stencil), ca2[level2]); + subset( + [&total_cells](const auto&, const auto&) + { + total_cells = 1; + }); + benchmark::DoNotOptimize(total_cells); + benchmark::DoNotOptimize(subset); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +template +void SUBSET_translate_and_intersect_and_project(benchmark::State& state) +{ + samurai::CellList cl1, cl2; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(cl1, max_index, level1, DEFAULT_X_INTERVALS); + gen_regular_intervals(cl2, max_index, level2, DEFAULT_X_INTERVALS); + samurai::CellArray ca1(cl1); + samurai::CellArray ca2(cl2); + + // Créer le stencil de translation + auto stencil = create_translation_stencil(); + + // Ajouter les statistiques + auto total_intervals = ca1[level1].nb_intervals() + ca2[level2].nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Level1"] = level1; + state.counters["Level2"] = level2; + state.counters["Input1_intervals"] = ca1[level1].nb_intervals(); + state.counters["Input2_intervals"] = ca2[level2].nb_intervals(); + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto total_cells = 0; + // intersection(translate(ca1, stencil), ca2) puis projection sur niveau supérieur + auto project_level = std::max(level1, level2) + 1; + auto subset = samurai::intersection(samurai::translate(ca1[level1], stencil), ca2[level2]).on(project_level); + subset( + [&total_cells](const auto&, const auto&) + { + total_cells = 1; + }); + benchmark::DoNotOptimize(total_cells); + benchmark::DoNotOptimize(subset); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +template +void SUBSET_translate_and_project(benchmark::State& state) +{ + samurai::CellList cl; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(cl, max_index, level, DEFAULT_X_INTERVALS); + samurai::CellArray ca(cl); + + // Créer le stencil de translation + auto stencil = create_translation_stencil(); + + // Ajouter les statistiques + auto total_intervals = ca[level].nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Level"] = level; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto total_cells = 0; + // Translate puis projection sur niveau supérieur + auto subset = samurai::translate(ca[level], stencil).on(level + 1); + subset( + [&total_cells](const auto&, const auto&) + { + total_cells = 1; + }); + benchmark::DoNotOptimize(total_cells); + benchmark::DoNotOptimize(subset); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +template +void SUBSET_self(benchmark::State& state) +{ + samurai::CellList cl; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(cl, max_index, level, DEFAULT_X_INTERVALS); + samurai::CellArray ca(cl); + + // Ajouter les statistiques + auto total_intervals = ca[level].nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Level"] = level; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto total_cells = 0; + auto subset = samurai::self(ca[level]); + subset( + [&total_cells](const auto&, const auto&) + { + total_cells = 1; + }); + benchmark::DoNotOptimize(total_cells); + benchmark::DoNotOptimize(subset); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +template +void SUBSET_self_and_project(benchmark::State& state) +{ + samurai::CellList cl; + int max_index = static_cast(state.range(0)); + gen_regular_intervals(cl, max_index, level, DEFAULT_X_INTERVALS); + samurai::CellArray ca(cl); + + // Ajouter les statistiques + auto total_intervals = ca[level].nb_intervals(); + state.counters["Dimension"] = dim; + state.counters["Level"] = level; + state.counters["Total_intervals"] = total_intervals; + state.counters["ns/interval"] = benchmark::Counter(total_intervals, + benchmark::Counter::kIsIterationInvariantRate | benchmark::Counter::kInvert); + + for (auto _ : state) + { + auto total_cells = 0; + // Self puis projection sur niveau supérieur + auto subset = samurai::self(ca[level]).on(level + 1); + subset( + [&total_cells](const auto&, const auto&) + { + total_cells = 1; + }); + benchmark::DoNotOptimize(total_cells); + benchmark::DoNotOptimize(subset); + } + + state.SetItemsProcessed(state.iterations() * static_cast(total_intervals)); +} + +/////////////////////////////////////////////////////////////////// +// Enregistrement des benchmarks +/////////////////////////////////////////////////////////////////// + +// Benchmarks pour les opérations ensemblistes en 1D (même niveau) - ~10k intervalles +BENCHMARK_TEMPLATE(SUBSET_set_diff_identical, 1, 0, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_diff_disjoint, 1, 0, 0)->Arg(10000); +// BENCHMARK_TEMPLATE(SUBSET_set_diff_single, 1, 0, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 1, 0, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 1, 0, 0)->Arg(10000); +// BENCHMARK_TEMPLATE(SUBSET_set_intersect_single, 1, 0, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 1, 0, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_union_disjoint, 1, 0, 0)->Arg(10000); +// BENCHMARK_TEMPLATE(SUBSET_set_union_single, 1, 0, 0)->Arg(10000); + +BENCHMARK_TEMPLATE(SUBSET_set_diff_identical, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_diff_disjoint, 1, 0, 1)->Arg(10000); +// BENCHMARK_TEMPLATE(SUBSET_set_diff_single, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 1, 0, 1)->Arg(10000); +// BENCHMARK_TEMPLATE(SUBSET_set_intersect_single, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_union_disjoint, 1, 0, 1)->Arg(10000); +// BENCHMARK_TEMPLATE(SUBSET_set_union_single, 1, 0, 1)->Arg(10000); + +// Benchmarks pour les opérations ensemblistes en 2D (même niveau) - ~10k intervalles +BENCHMARK_TEMPLATE(SUBSET_set_diff_identical, 2, 0, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_diff_disjoint, 2, 0, 0)->Arg(2000); +// BENCHMARK_TEMPLATE(SUBSET_set_diff_single, 2, 0, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 2, 0, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 2, 0, 0)->Arg(2000); +// BENCHMARK_TEMPLATE(SUBSET_set_intersect_single, 2, 0, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 2, 0, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_union_disjoint, 2, 0, 0)->Arg(2000); +// BENCHMARK_TEMPLATE(SUBSET_set_union_single, 2, 0, 0)->Arg(2000); + +BENCHMARK_TEMPLATE(SUBSET_set_diff_identical, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_diff_disjoint, 2, 0, 1)->Arg(2000); +// BENCHMARK_TEMPLATE(SUBSET_set_diff_single, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 2, 0, 1)->Arg(2000); +// BENCHMARK_TEMPLATE(SUBSET_set_intersect_single, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_union_disjoint, 2, 0, 1)->Arg(2000); +// BENCHMARK_TEMPLATE(SUBSET_set_union_single, 2, 0, 1)->Arg(2000); + +// Benchmarks pour les opérations ensemblistes en 3D (même niveau) - ~10k intervalles +BENCHMARK_TEMPLATE(SUBSET_set_diff_identical, 3, 0, 0)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_diff_disjoint, 3, 0, 0)->Arg(45); +// BENCHMARK_TEMPLATE(SUBSET_set_diff_single, 3, 0, 0)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 3, 0, 0)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 3, 0, 0)->Arg(45); +// BENCHMARK_TEMPLATE(SUBSET_set_intersect_single, 3, 0, 0)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 3, 0, 0)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_union_disjoint, 3, 0, 0)->Arg(45); +// BENCHMARK_TEMPLATE(SUBSET_set_union_single, 3, 0, 0)->Arg(45); + +BENCHMARK_TEMPLATE(SUBSET_set_diff_identical, 3, 0, 1)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_diff_disjoint, 3, 0, 1)->Arg(45); +// BENCHMARK_TEMPLATE(SUBSET_set_diff_single, 3, 0, 1)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 3, 0, 1)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 3, 0, 1)->Arg(45); +// BENCHMARK_TEMPLATE(SUBSET_set_intersect_single, 3, 0, 1)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 3, 0, 1)->Arg(45); +BENCHMARK_TEMPLATE(SUBSET_set_union_disjoint, 3, 0, 1)->Arg(45); +// BENCHMARK_TEMPLATE(SUBSET_set_union_single, 3, 0, 1)->Arg(45); + +// Benchmarks pour les opérations géométriques (niveau unique) +BENCHMARK_TEMPLATE(SUBSET_translate, 1, 0)->Arg(10000); // ~10k intervalles +BENCHMARK_TEMPLATE(SUBSET_translate, 2, 0)->Arg(2000); // ~10k intervalles +BENCHMARK_TEMPLATE(SUBSET_translate, 3, 0)->Arg(45); // ~10k intervalles + +BENCHMARK_TEMPLATE(SUBSET_translate_and_project, 1, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_project, 2, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_project, 3, 0)->Arg(45); + +BENCHMARK_TEMPLATE(SUBSET_self, 1, 0)->Arg(10000); // ~10k intervalles +BENCHMARK_TEMPLATE(SUBSET_self, 2, 0)->Arg(2000); // ~10k intervalles +BENCHMARK_TEMPLATE(SUBSET_self, 3, 0)->Arg(45); // ~10k intervalles + +BENCHMARK_TEMPLATE(SUBSET_self_and_project, 1, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_self_and_project, 2, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_self_and_project, 3, 0)->Arg(45); + +// Benchmarks géométriques avec niveaux mixtes (niveau 0 vs autre niveau) +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect, 1, 0, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect, 2, 0, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect, 3, 0, 0)->Arg(45); + +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect, 2, 0, 2)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect, 2, 0, 10)->Arg(2000); // this bench is weird : the perf ??? maybe a bug. + +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect_and_project, 1, 0, 0)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect_and_project, 2, 0, 0)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_translate_and_intersect_and_project, 3, 0, 0)->Arg(45); + +/////////////////////////////////////////////////////////////////// +// Benchmarks avec niveaux mixtes (intéressants pour comparer les niveaux) +/////////////////////////////////////////////////////////////////// + +// Benchmarks 1D : niveau 0 vs niveau 1 +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 1, 0, 1)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 1, 0, 1)->Arg(10000); + +// Benchmarks 1D : niveau 0 vs niveau 2 +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 1, 0, 2)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 1, 0, 2)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 1, 0, 2)->Arg(10000); + +// Benchmarks 1D : niveau 1 vs niveau 2 +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 1, 1, 2)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 1, 1, 2)->Arg(10000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 1, 1, 2)->Arg(10000); + +// Benchmarks 2D : niveau 0 vs niveau 1 +BENCHMARK_TEMPLATE(SUBSET_set_intersect_identical, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_intersect_disjoint, 2, 0, 1)->Arg(2000); +BENCHMARK_TEMPLATE(SUBSET_set_union_identical, 2, 0, 1)->Arg(2000); + +// Benchmarks géométriques avec niveaux mixtes