Skip to content

experimental/adrh: the ADRH element kernel as Kokkos kernels, with colored assembly - #103

Open
cekees wants to merge 1 commit into
mainfrom
adrh-kokkos
Open

cekees wants to merge 1 commit into
mainfrom
adrh-kokkos

Conversation

@cekees

@cekees cekees commented Oct 24, 2026

Copy link
Copy Markdown
Owner

What

The prototype's masked element kernel runs under Kokkos: threads on a CPU, a GPU through CUDA, from the same headers. Experimental, not part of the proteus build.

  • masked.h: the loop body is now elementMaskedOne; elementKernelMasked is the loop over it. portable.h makes the functions KOKKOS_INLINE_FUNCTION under ADRH_USE_KOKKOS.
  • kokkos_kernel.h: elementKernelKokkos (the prototype's interface) and assembleColored, which colors the elements by node sharing, and in one launch per color computes each element and adds it to the global residual and a block-CSR Jacobian. No atomics.
  • module_kokkos.cpp: adrh_kokkos, same calling convention as adrh_proto. ADRH_MODULE=adrh_kokkos python ad_regression.py (or compare_with_python.py) runs the existing Proteus comparison on it. golden.py compares any two builds.
  • bench_kokkos.cpp, build_kokkos.sh, README section.

Decision this implements: Kokkos with element coloring for threads and devices in the generated kernels (cekees, 2026-10-24).

Results

Details and the table are in experimental/adrh/README.md; raw logs are beside the campaign notes.

  • The port is the prototype. Kokkos element kernel is bitwise the host kernel on the CPU for all four functors. Against Proteus: element residual and Jacobian 8.6e-16 and 6.0e-16; the advection-diffusion regression in 2D and 3D, all seven boundary treatments, agrees with the Proteus model to 1.2e-14 or better, L2 rates 1.85 to 2.00.
  • Same bits at every thread count (1 to 96) and on both RTX 6000 Ada cards, run to run.
  • Speed: 11x at 12 threads on an M4 Max, 52 to 63x on 96 Zen 4 threads. One Ada card equals the 96-core node on Poisson and the coupled system, is 3x slower on the five-component chain.
  • Bits across platforms depend on fused multiply-add. With contraction off (-ffp-contract=off, --fmad=false), Apple arm64, x86-64 and the GPU give identical bits for Poisson and the five-component chain, and identical Jacobians for all four. The two kernels that call sin differ in the residual's last bit between C libraries and CUDA.

A finding in the host prototype

The compile-time loop helpers were left as real calls whenever the kernel was reached through a member function, which pushes every array of the element into memory: the Poisson kernel ran 3.2x slower there than in a plain loop. Kokkos was not the cause. They are always_inline now, which also speeds the host prototype (masked coupled system 3.4 to 1.3 microseconds per element, masked five-component chain 6.6 to 2.5). Host outputs are bit-identical to before except the 2D advection-diffusion arrays, which move by 3e-16 (FMA contraction under the new inlining). affineP1 uses if constexpr for its 2D branch (the dead 3D branch indexed out of range).

Not done

No pytest: the directory's checks are scripts, and a Kokkos CI leg needs the build-system decision (kernels in a CMake-built library). The CUDA build was run on ceds-model only.

🤖 Generated with Claude Code

…devices), with colored assembly

The per-element body of the masked kernel becomes elementMaskedOne, called
from the host loop and from Kokkos functors; ADRH_FN is KOKKOS_INLINE_FUNCTION
under ADRH_USE_KOKKOS, so the headers are one source for both. New:
kokkos_kernel.h (element kernel; fused assembly into the global residual and a
block-CSR Jacobian with greedy element coloring, no atomics), bench_kokkos.cpp,
module_kokkos.cpp (adrh_kokkos, the host module's interface, so ad_regression.py
and compare_with_python.py run on it with ADRH_MODULE), golden.py, build_kokkos.sh.

The constexpr_for helpers and the per-element function are always_inline:
reached through a member function they stayed real calls and the Poisson kernel
ran 3.2x slower than in a plain loop. The same change makes the host prototype
faster (masked coupled system 3.4 to 1.3 us per element, masked five-component
chain 6.6 to 2.5). affineP1 uses if constexpr for the 2D branch.

Checked: the Kokkos kernel is bitwise the host kernel on the CPU; colored
assembly has the same bits at every thread count and on both GPUs; element
residual and Jacobian against Proteus 8.6e-16 and 6.0e-16; the advection-
diffusion regression, 2D and 3D, seven boundary treatments, within 1.2e-14 of
the Proteus model. With FMA contraction off, Apple arm64, x86-64 and an NVIDIA
GPU give identical bits for the kernels without transcendental functions.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant