C3 — Reduce an array, the same way on either backend#
Sum an aether SoA array on the GPU with a multi-level CUDA reduction, or on the CPU with a cache-padded OpenMP one – same call, same answer.
Time: ~2 min · Runs on: CUDA GPU or CPU (OpenMP) · You need: C2
In CUDA mode, eagle::cuda::Reduction runs a multi-level GPU reduction over
the uploaded array:
// Blocking multi-level reduction on the GPU: returns the scalar sum.
const T total = eagle::cuda::Reduction::reduceBlocking<T, Sum>(arr, T(0), stream);
In pure-C++ mode, eagle::cpu::Reduction runs the cache-padded OpenMP
reduction over the host-resident array – same operator, same result:
// Cache-padded OpenMP reduction over the host-resident array.
const T total = eagle::cpu::Reduction<T, Sum>::reduce(arr.hostView().as_const(), T(0));
What it printed#
03_reduction (CUDA): sum(1..1000)=500500 (expected 500500) : OK
What just happened#
Reductiontook the same aether array and the same combine operator on both backends; only the class name (eagle::cuda::Reductionvs.eagle::cpu::Reduction) differs between the two source files.The GPU build reduces in multiple levels (block, then grid); the CPU build pads each OpenMP thread’s partial sum to its own cache line to avoid false sharing – two different implementations reaching the same
sum(1..1000).Neither build re-sums on the host afterwards: the reduction itself is the answer, not a seed for a second pass.
Try this#
Change the summed range from 1..1000 to 1..1 and rebuild: the expected total becomes 1 on both backends, the smallest possible reduction.
Next#
C4 – embedding a compiled plugin in your own C++ program, in C4 — Embed a compiled kernel in your own C++ program – the other side of eagle: a binary ABI a C++ host can load with no aether headers, no Python, and no code generator at build or run time. deeper: CUDA graphs for the concepts behind capture/replay, and the Module: reduce / Module: cpu module guides for the reduction and host APIs.