Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
dec18a3
running test prim_to_cons, (pre cleanup)
tim-pearson Mar 26, 2026
8ffb5b4
gtest for small N=16 testcase prim_to_cons
tim-pearson Mar 26, 2026
71f9684
PrimToConsVectorized benchmark
tim-pearson Mar 30, 2026
3c3f995
PrimToConsVectorized speedup against scalar over plateau
tim-pearson Mar 30, 2026
c2590c2
PrimToConsWorstRem benchmark added
tim-pearson Mar 31, 2026
552ff17
kokkos version 4.7.1 -> 5.0.0
tim-pearson Mar 31, 2026
f4f1cba
Seprate global utils for benchmark and tests
tim-pearson Mar 31, 2026
a582fb7
include utils directory
tim-pearson Mar 31, 2026
f6a7812
pass cons/prim arrays to prim_to_cons kernel, updated plots
tim-pearson Apr 1, 2026
794dc3d
simd compatible store and load functions
tim-pearson Apr 1, 2026
ec4e16c
to_cons optimized, negligible slowdown comapred to fully inlined version
tim-pearson Apr 2, 2026
d3c6b65
forcw inline for load, to_cons, store
tim-pearson Apr 2, 2026
d71e630
merging main -> vec-prim_to_cons
tim-pearson Apr 3, 2026
f6b1dc9
inlined vectorized prim_to_cons passing tests
tim-pearson Apr 3, 2026
d62f344
prim_to_cons_vec passing tests with remainders
tim-pearson Apr 3, 2026
ce44abb
merging vec-prim_to_cons-CUDA
tim-pearson Apr 3, 2026
cf3408b
constexp for scalar remainder, cons_to_prim implementation
tim-pearson Apr 7, 2026
aa8f01b
cons_to_prim passing tests
tim-pearson Apr 7, 2026
b002276
neglible difference cons_to_prim vect<->scalar
tim-pearson Apr 7, 2026
6b77391
prim_to_cons + cons_to_prim vectorized
tim-pearson Apr 8, 2026
2dfba79
first implementation time_step_vec, passing tests for skx
tim-pearson Apr 8, 2026
29487b9
optimization: max reduction + division outside kernal loop
tim-pearson Apr 10, 2026
e7c31f8
use reduction_idenitiy time step cuda compatibilty
tim-pearson Apr 10, 2026
5ce1655
vectorized godunov with benchmark + test
tim-pearson Apr 10, 2026
344a166
hllc select for conditionals
tim-pearson Apr 13, 2026
0a41e43
remove constexpr for remainders, add godunov remainder test
tim-pearson Apr 15, 2026
5c18d59
update setup scripts a100 skx, vectorized simulation, global utils
tim-pearson Apr 15, 2026
45a86fe
remove constexpr for remainder, to create PR
tim-pearson Apr 16, 2026
3169446
merging main -> vec-prim_to_cons
tim-pearson Apr 16, 2026
447a006
Merge branch 'main' into vec-prim_to_cons
tpadioleau Apr 19, 2026
dbd51c3
Merge branch 'main' into vec-prim_to_cons
tpadioleau Apr 19, 2026
1465cf6
only use OMP_PLACES=numa_domains
tim-pearson Apr 20, 2026
644d90d
Update euler_operators/cons_to_prim.hpp
tim-pearson Apr 20, 2026
69f4cfd
merging main with updated clang-tidy-ci, remove run.sh for skx
tim-pearson Apr 21, 2026
ab84031
remove test/ dir duplicate, clang tidy + format
tim-pearson Apr 21, 2026
bdcc031
shellcheck, pylint
tim-pearson Apr 21, 2026
d8e94c5
compare helper for cons and prim arrays in tests
tim-pearson Apr 22, 2026
3c51ebe
(pylint):pip install pandas, (clang-tidy): widening cast fix
tim-pearson Apr 22, 2026
e6d8594
merged updated vec-prim_to_cons branch
tim-pearson Apr 22, 2026
6807707
Udpate adastra setup scripts and plot.py
tim-pearson Apr 27, 2026
66d5ce2
MI300 4871378 benchmark with current run_bench.sh
tim-pearson Apr 27, 2026
d4faebd
Add run_test.sh for mi300
tim-pearson Apr 27, 2026
32edc47
Optimized hllc and godunov implementations
tim-pearson Apr 29, 2026
5237f24
Updated Godunov tests for opti
tim-pearson Apr 29, 2026
ae2a189
Merge main->vec-godunov
tim-pearson Apr 30, 2026
63e0c83
Formatting
tim-pearson Apr 30, 2026
ff5f577
Remove casts in hllc
tim-pearson Apr 30, 2026
0a261cd
Update bm save paths, consistency adastra<->ruche
tim-pearson Apr 30, 2026
14d0328
merge main->vec-godunov
tim-pearson May 5, 2026
d3a9149
Use common mapping + data_handle in godunov
tim-pearson May 5, 2026
7720339
Flatten loop for compare() in test_godunov
tim-pearson May 5, 2026
0ecd9bc
Uncomment prepare scripts sections, format hllc headers
tim-pearson May 5, 2026
1bfd882
Use APU Kokkos Arch flag for mi300a
tim-pearson May 5, 2026
f0b1992
linting and iwyu
tim-pearson May 5, 2026
3fd27af
kokkos simd include bm euler_simulation fro iwyu
tim-pearson May 5, 2026
33077da
Try Kokkos_SIMD.hpp for iwyu
tim-pearson May 5, 2026
9f49653
test_godunov.cpp update inlcude for iwyu
tim-pearson May 6, 2026
dd14468
benchmark_godunov.cpp update inlcude for iwyu
tim-pearson May 6, 2026
13017f3
godunov.hpp update inlcude for iwyu
tim-pearson May 6, 2026
0eb64fe
benchmark_euler_simulation.cpp update include for iwyu
tim-pearson May 6, 2026
6ca6d04
benchmark_godunov.cpp update include for iwyu
tim-pearson May 6, 2026
e267113
test_godunov.cpp update include for iwyu
tim-pearson May 6, 2026
c05168d
hllc.hpp update include for iwyu
tim-pearson May 6, 2026
db6c671
Specify 8 to --parallel flag, remove old modules, fix inlcudes in hllc
tim-pearson May 7, 2026
a95a503
Remove inti setup scripts
tim-pearson May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions benchmarks/benchmark_euler_simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,55 @@ void EulerSimulation(benchmark::State& state)
set_constant_cells_processed(state, size(cons_arrays));
}

void EulerSimulationVectorized(benchmark::State& state)
{
auto const nx = int_cast<index_t>(state.range());
real_t const cfl_factor = 0.49;
real_t const gamma = 1.4;
auto nn = static_cast<std::size_t>(nx) + 2;
std::size_t const n3 = nn * nn * nn;

real_t const dx = 1. / static_cast<real_t>(nx);
PerfectGas<real_t> const eos(gamma);
UniformMesh3d<real_t> const mesh(dx, dx, dx);
hllc const riemann_solver;
Kokkos::DefaultExecutionSpace const exec_space;
EulerPrimArrays const prims_alloc = create_prim_arrays_1d<real_t>(exec_space, n3);
EulerPrimArrays const prim_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(prims_alloc, nx + 2, nx + 2, nx + 2);
EulerConsArrays const cons_alloc = create_cons_arrays_1d<real_t>(exec_space, n3);
EulerConsArrays const cons_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(cons_alloc, nx + 2, nx + 2, nx + 2);

init_implode(exec_space, prim_arrays, mesh);
prim_to_cons_vec(exec_space, as_const(prim_arrays), cons_arrays, eos);
exec_space.fence();

for ([[maybe_unused]] auto _ : state) {
real_t const dt = time_step_vec(exec_space, as_const(prim_arrays), eos, mesh);

godunov_vec(
exec_space,
as_const(prim_arrays),
cons_arrays,
eos,
mesh,
riemann_solver,
cfl_factor * dt);

boundary_conditions_periodic(exec_space, cons_arrays, 1);

cons_to_prim_vec(exec_space, as_const(cons_arrays), prim_arrays, eos);
exec_space.fence();
}
set_constant_cells_processed(state, size(cons_arrays));
}

} // namespace

BENCHMARK(EulerSimulation)->UseRealTime()->DenseRange(8, 31, 8)->DenseRange(32, 320, 32);
BENCHMARK(EulerSimulationVectorized)->UseRealTime()->DenseRange(8, 31, 8)->DenseRange(32, 320, 32);
121 changes: 120 additions & 1 deletion benchmarks/benchmark_godunov.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,125 @@ void Godunov(benchmark::State& state)
set_constant_bytes_processed(state, size_bytes(prim_arrays) + (2 * size_bytes(cons_arrays)));
}

void GodunovWorstRem(benchmark::State& state)
{
auto const n = int_cast<index_t>(state.range() + 2);
PerfectGas<real_t> const eos(1.4);
UniformMesh3d<real_t> const mesh(1., 1., 1.);
real_t const dt = 1E-9;
auto nn = static_cast<std::size_t>(n);
std::size_t const n3 = nn * nn * nn;

Kokkos::DefaultExecutionSpace const exec_space;
EulerPrimArrays const prims_alloc = create_prim_arrays_1d<real_t>(exec_space, n3);
EulerPrimArrays const prim_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(prims_alloc, n, n, n);
EulerConsArrays const cons_alloc = create_cons_arrays_1d<real_t>(exec_space, n3);
EulerConsArrays const cons_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(cons_alloc, n, n, n);
EulerPrim<real_t> const prim {.d = 1, .p = 1, .ux0 = 0, .ux1 = 0, .ux2 = 0};
init_from_state(exec_space, prim_arrays, prim);
init_from_state(exec_space, cons_arrays, to_cons(prim, eos.internal_energy(prim.d, prim.p)));
exec_space.fence();

for ([[maybe_unused]] auto _ : state) {
godunov(exec_space, as_const(prim_arrays), cons_arrays, eos, mesh, hllc(), dt);
exec_space.fence();
benchmark::ClobberMemory();
}

set_constant_cells_processed(state, size(cons_arrays));
set_constant_bytes_processed(state, size_bytes(prim_arrays) + (2 * size_bytes(cons_arrays)));
}

void GodunovVectorized(benchmark::State& state)
{
auto const n = int_cast<index_t>(state.range() + 2);
PerfectGas<real_t> const eos(1.4);
UniformMesh3d<real_t> const mesh(1., 1., 1.);
real_t const dt = 1E-9;
auto nn = static_cast<std::size_t>(n);
std::size_t const n3 = nn * nn * nn;

Kokkos::DefaultExecutionSpace const exec_space;
EulerPrimArrays const prims_alloc = create_prim_arrays_1d<real_t>(exec_space, n3);
EulerPrimArrays const prim_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(prims_alloc, n, n, n);
EulerConsArrays const cons_alloc = create_cons_arrays_1d<real_t>(exec_space, n3);
EulerConsArrays const cons_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(cons_alloc, n, n, n);
EulerPrim<real_t> const prim {.d = 1, .p = 1, .ux0 = 0, .ux1 = 0, .ux2 = 0};
init_from_state(exec_space, prim_arrays, prim);
init_from_state(exec_space, cons_arrays, to_cons(prim, eos.internal_energy(prim.d, prim.p)));
exec_space.fence();

for ([[maybe_unused]] auto _ : state) {
godunov_vec(exec_space, as_const(prim_arrays), cons_arrays, eos, mesh, hllc(), dt);
exec_space.fence();
benchmark::ClobberMemory();
}

set_constant_cells_processed(state, size(cons_arrays));
set_constant_bytes_processed(state, size_bytes(prim_arrays) + (2 * size_bytes(cons_arrays)));
}

void GodunovVectorizedWorstRem(benchmark::State& state)
{
auto const n = int_cast<index_t>(state.range() + 2);
PerfectGas<real_t> const eos(1.4);
UniformMesh3d<real_t> const mesh(1., 1., 1.);
real_t const dt = 1E-9;

auto nn = static_cast<std::size_t>(n);
std::size_t const n3 = nn * nn * nn;

Kokkos::DefaultExecutionSpace const exec_space;
EulerPrimArrays const prims_alloc = create_prim_arrays_1d<real_t>(exec_space, n3);
EulerPrimArrays const prim_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(prims_alloc, n, n, n);
EulerConsArrays const cons_alloc = create_cons_arrays_1d<real_t>(exec_space, n3);
EulerConsArrays const cons_arrays = to_mdspan<Kokkos::mdspan<
real_t,
Kokkos::dextents<index_t, 3>,
Kokkos::layout_left>>(cons_alloc, n, n, n);
EulerPrim<real_t> const prim {.d = 1, .p = 1, .ux0 = 0, .ux1 = 0, .ux2 = 0};
init_from_state(exec_space, prim_arrays, prim);
init_from_state(exec_space, cons_arrays, to_cons(prim, eos.internal_energy(prim.d, prim.p)));
exec_space.fence();

for ([[maybe_unused]] auto _ : state) {
godunov_vec(exec_space, as_const(prim_arrays), cons_arrays, eos, mesh, hllc(), dt);
exec_space.fence();
benchmark::ClobberMemory();
}

set_constant_cells_processed(state, size(cons_arrays));
set_constant_bytes_processed(state, size_bytes(prim_arrays) + (2 * size_bytes(cons_arrays)));
}

} // namespace

BENCHMARK(Godunov)->UseRealTime()->DenseRange(8, 31, 8)->DenseRange(32, 320, 32);
BENCHMARK(Godunov)
->UseRealTime()
->DenseRange(8, 31, 8)
->DenseRange(32, 127, 16)
->DenseRange(128, 320, 32);

BENCHMARK(GodunovVectorized)
->UseRealTime()
->DenseRange(8, 31, 8)
->DenseRange(32, 127, 16)
->DenseRange(128, 320, 32);

BENCHMARK(GodunovWorstRem)->UseRealTime()->DenseRange(7, 31, 8)->DenseRange(31, 320, 32);
BENCHMARK(GodunovVectorizedWorstRem)->UseRealTime()->DenseRange(7, 31, 8)->DenseRange(31, 320, 32);
147 changes: 147 additions & 0 deletions euler_operators/godunov.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <type_traits>

#include <Kokkos_Core.hpp>
#include <Kokkos_SIMD.hpp>
#include <euler_arrays.hpp>
#include <hllc.hpp>
#include <perfect_gas.hpp>
Expand All @@ -28,6 +29,9 @@ void godunov(
hllc const& riemann_solver,
T const dt)
{
namespace KE = Kokkos::Experimental;
using simd_t = KE::simd<T>;

Kokkos::Array<T, 3> const ds = {mesh.ds0(), mesh.ds1(), mesh.ds2()};
T const dtodv = dt / mesh.dv();

Expand Down Expand Up @@ -90,3 +94,146 @@ void godunov(
store(cons, cons_arrays, i, j, k);
});
}

template <class SimdType, class T, class IndexType, std::size_t E0, std::size_t E1, std::size_t E2>
void godunov_kernel(
Kokkos::DefaultExecutionSpace const& exec_space,
EulerPrimArrays<Kokkos::mdspan<
T const,
Kokkos::extents<IndexType, E0, E1, E2>,
Kokkos::layout_left>> const& prim_arrays,
EulerConsArrays<Kokkos::mdspan<
T,
Kokkos::extents<IndexType, E0, E1, E2>,
Kokkos::layout_left>> const& cons_arrays,
IndexType nx_begin,
IndexType nx_end,
PerfectGas<T> const& eos,
UniformMesh3d<T> const& mesh,
hllc const& riemann_solver,
T const dt)
{
constexpr IndexType width = SimdType::size();
IndexType const nx_blocks = (nx_end - nx_begin) / width;
IndexType const ny = prim_arrays.d.extent(1);
IndexType const nz = prim_arrays.d.extent(2);

// layout_left strides: stride in y = extent(0), stride in z = extent(0)*extent(1)
IndexType const stride_y = prim_arrays.d.extent(0);
IndexType const stride_z = prim_arrays.d.extent(0) * prim_arrays.d.extent(1);

Kokkos::Array<T, 3> const ds = {mesh.ds0(), mesh.ds1(), mesh.ds2()};
T const dtodv = dt / mesh.dv();

Kokkos::layout_left::mapping const common_mapping = prim_arrays.d.mapping();
EulerPrimArrays const prim_ptrs = data_handle(prim_arrays);
EulerConsArrays const cons_ptrs = data_handle(cons_arrays);

Kokkos::parallel_for(
"godunov_kernel",
Kokkos::MDRangePolicy<
Kokkos::Rank<3, Kokkos::Iterate::Left, Kokkos::Iterate::Left>,
Kokkos::IndexType<IndexType>>(
exec_space,
{0, 1, 1},
{nx_blocks, ny - 1, nz - 1}), // nx_begin already acouting for ghost cells
KOKKOS_LAMBDA(IndexType const bi, IndexType const j, IndexType const k) {
IndexType const base = common_mapping(nx_begin + (bi * width), j, k);
EulerPrim<SimdType> const prim = load<SimdType>(prim_arrays, base);
EulerFlux<SimdType> flux {};

{
EulerPrim const prim_L = load<SimdType>(prim_arrays, base - 1);
EulerPrim const prim_R = load<SimdType>(prim_arrays, base + 1);
EulerFlux const flux_L = riemann_solver(dir_t<0>(), eos, prim_L, prim);
EulerFlux const flux_R = riemann_solver(dir_t<0>(), eos, prim, prim_R);
flux.d += ds[0] * (flux_R.d - flux_L.d);
flux.e += ds[0] * (flux_R.e - flux_L.e);
flux.mx0 += ds[0] * (flux_R.mx0 - flux_L.mx0);
flux.mx1 += ds[0] * (flux_R.mx1 - flux_L.mx1);
flux.mx2 += ds[0] * (flux_R.mx2 - flux_L.mx2);
}
{
EulerPrim const prim_L = load<SimdType>(prim_arrays, base - stride_y);
EulerPrim const prim_R = load<SimdType>(prim_arrays, base + stride_y);
EulerFlux const flux_L = riemann_solver(dir_t<1>(), eos, prim_L, prim);
EulerFlux const flux_R = riemann_solver(dir_t<1>(), eos, prim, prim_R);
flux.d += ds[1] * (flux_R.d - flux_L.d);
flux.e += ds[1] * (flux_R.e - flux_L.e);
flux.mx0 += ds[1] * (flux_R.mx0 - flux_L.mx0);
flux.mx1 += ds[1] * (flux_R.mx1 - flux_L.mx1);
flux.mx2 += ds[1] * (flux_R.mx2 - flux_L.mx2);
}
{
EulerPrim const prim_L = load<SimdType>(prim_arrays, base - stride_z);
EulerPrim const prim_R = load<SimdType>(prim_arrays, base + stride_z);
EulerFlux const flux_L = riemann_solver(dir_t<2>(), eos, prim_L, prim);
EulerFlux const flux_R = riemann_solver(dir_t<2>(), eos, prim, prim_R);
flux.d += ds[2] * (flux_R.d - flux_L.d);
flux.e += ds[2] * (flux_R.e - flux_L.e);
flux.mx0 += ds[2] * (flux_R.mx0 - flux_L.mx0);
flux.mx1 += ds[2] * (flux_R.mx1 - flux_L.mx1);
flux.mx2 += ds[2] * (flux_R.mx2 - flux_L.mx2);
}

EulerCons cons = load<SimdType>(cons_ptrs, base);
cons.d -= dtodv * flux.d;
cons.e -= dtodv * flux.e;
cons.mx0 -= dtodv * flux.mx0;
cons.mx1 -= dtodv * flux.mx1;
cons.mx2 -= dtodv * flux.mx2;
store<SimdType>(cons, cons_ptrs, base);
});
}

template <class T, class IndexType, std::size_t E0, std::size_t E1, std::size_t E2>
void godunov_vec(
Kokkos::DefaultExecutionSpace const& exec_space,
EulerPrimArrays<Kokkos::mdspan<
T const,
Kokkos::extents<IndexType, E0, E1, E2>,
Kokkos::layout_left>> const& prim_arrays,
EulerConsArrays<Kokkos::mdspan<
T,
Kokkos::extents<IndexType, E0, E1, E2>,
Kokkos::layout_left>> const& cons_arrays,
PerfectGas<T> const& eos,
UniformMesh3d<T> const& mesh,
hllc const& riemann_solver,
T const dt)
{
namespace KE = Kokkos::Experimental;
using simd_t = KE::simd<T>;
using simd_scalar_t = KE::basic_simd<T, KE::simd_abi::scalar>;

// interior x-range is [1, nx-1)
IndexType const nx = prim_arrays.d.extent(0);
IndexType const nx_begin = 1;
IndexType const nx_inner = nx - 2; // number of interior cells
IndexType const vec_end = nx_begin + ((nx_inner / simd_t::size()) * simd_t::size());
IndexType const nx_end = nx - 1;

godunov_kernel<simd_t>(
exec_space,
prim_arrays,
cons_arrays,
nx_begin,
vec_end,
eos,
mesh,
riemann_solver,
dt);

if (vec_end < nx_end) {
godunov_kernel<simd_scalar_t>(
exec_space,
prim_arrays,
cons_arrays,
vec_end,
nx_end,
eos,
mesh,
riemann_solver,
dt);
}
}
Loading