Neko 1.99.6
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
gs_nvshmem_kernels.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2024-2026, The Neko Authors
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16
17 * Neither the name of the authors nor the names of its
18 contributors may be used to endorse or promote products derived
19 from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33*/
34
35#ifndef __GS_NVSHMEM_KERNELS__
36#define __GS_NVSHMEM_KERNELS__
37
38#include <nvshmemx.h>
39
40/*
41 * Push kernels with rank-indexed signaling.
42 *
43 * Signaling uses two symmetric arrays of pe_size slots, indexed by the
44 * REMOTE PE's rank (so peer lists need not be uniform in length across
45 * ranks, and the symmetric allocations are collective-safe):
46 * - doneSig = &done_sig[my_rank] on the destination: set to iter by our
47 * put_signal when our slab has landed there.
48 * - readySlot = &ready_sig[destRank] locally: set to iter by the
49 * destination once it has consumed our round-iter slab.
50 * The round counter iter advances once per gs op (lockstep across ranks),
51 * and all waits use CMP_GE, so no cross-rank counter matching is needed.
52 *
53 * Packing is NOT done here: all peer slabs are packed by one bulk kernel
54 * on the main stream in nbsend, into the round's parity half of the
55 * double-buffered send buffer (see gs_device_shmem.F90). That orders every
56 * read of the shared buffer u before any unpack writes u. Packing inside
57 * the push kernel, gated on the remote ready signal, let an unpack from a
58 * fast peer modify u before the pack for a slow peer had read it -- for a
59 * dof shared with both peers the slow peer then received an already
60 * partially reduced value (observed as divergence at large rank counts,
61 * where multi-peer dofs and round-level skew are common).
62 *
63 * The ready wait below therefore gates only the put: the destination posts
64 * ready(iter-1) once it has consumed our round iter-1 slab, so its recv
65 * slab may be overwritten. The pack needs no remote gate; see the nbsend
66 * comment in gs_device_shmem.F90 for why the parity slab has always
67 * drained by the time it is repacked.
68 *
69 * These are SINGLE-BLOCK kernels (launched with one block); single-block
70 * transfers were found to perform best at gs slab sizes.
71 */
72
73template< typename T >
75 const T * __restrict__ src,
76 const size_t n,
77 const int destRank,
78 uint64_t iter,
81
82template<>
84 const float * __restrict__ src,
85 const size_t n,
86 const int destRank,
87 uint64_t iter,
90{
91
92 /* Wait until destRank has consumed our previous round (see note above) */
93 if (threadIdx.x == 0) {
95 }
97
98 /* Push data and set done_sig[my_rank] = iter on the destination */
100 doneSig, iter,
102}
103
104template<>
106 const double * __restrict__ src,
107 const size_t n,
108 const int destRank,
109 uint64_t iter,
112{
113
114 /* Wait until destRank has consumed our previous round (see note above) */
115 if (threadIdx.x == 0) {
117 }
119
120 /* Push data and set done_sig[my_rank] = iter on the destination */
122 doneSig, iter,
124}
125
126/* Wait until the slab from a recv peer has landed (doneSlot is our local
127 done_sig[src] slot, set by the peer's put_signal) */
130{
131 if (blockIdx.x==0 && threadIdx.x == 0) {
133 }
134}
135
136/* Post our ready signal to the peer we receive from: sets
137 ready_sig[my_rank] = iter on srcRank, allowing it to put its next round
138 into our recv slab. Launched after the unpack on the same stream. */
140 uint64_t iter,
141 const int srcRank)
142{
143 if (blockIdx.x==0 && threadIdx.x == 0) {
145 }
146}
147
148#endif
__global__ void ale_add_kinematics_kernel(const int n, T *__restrict__ wx, T *__restrict__ wy, T *__restrict__ wz, const T *__restrict__ x_ref, const T *__restrict__ y_ref, const T *__restrict__ z_ref, const T *__restrict__ phi, const T *__restrict__ x, const T *__restrict__ y, const T *__restrict__ z, const kinematics_params_t kin_params)
__syncthreads()
__global__ void pushShmemKernelWait(uint64_t iter, uint64_t *doneSlot)
__global__ void postReadyShmemKernel(uint64_t *readySlot, uint64_t iter, const int srcRank)
__global__ void pushShmemKernel(T *dest, const T *__restrict__ src, const size_t n, const int destRank, uint64_t iter, uint64_t *doneSig, uint64_t *readySlot)