Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
ax_helm_kernel.h
Go to the documentation of this file.
1#ifndef __MATH_AX_HELM_KERNEL_H__
2#define __MATH_AX_HELM_KERNEL_H__
3/*
4 Copyright (c) 2021-2026, The Neko Authors
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13
14 * Redistributions in binary form must reproduce the above
15 copyright notice, this list of conditions and the following
16 disclaimer in the documentation and/or other materials provided
17 with the distribution.
18
19 * Neither the name of the authors nor the names of its
20 contributors may be used to endorse or promote products derived
21 from this software without specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.
35*/
36
37#include "elem_block.h"
38#include "dmma_kernel.h"
39#include "dmma_tma_kernel.h"
40
41/*
42 * A note on elements per block for the vector kstep kernels.
43 *
44 * These hold three times the register blocked state of the scalar ones -- six
45 * T[LX] arrays rather than two -- and measure at 254-255 registers on sm_90
46 * for every lx from 8 up, spilling at 10, 12, 14 and 16. Blocking is therefore
47 * not expected to buy much: it does not change registers per thread, only
48 * threads per block, so at 255 registers the occupancy is the same either way
49 * and all it saves is loading the derivative matrices once per block instead
50 * of once per element.
51 *
52 * They are swept anyway, over the same elem_block<> candidates as the scalar
53 * kernels. "Not expected to buy much" is a prediction, and pinning it at build
54 * time is a prediction the tuner can never check. elem_block<>'s thread clamp
55 * keeps every candidate inside the shared memory budget at every lx -- the
56 * widest case, lx = 11 at four elements per block, comes to 37 kB against the
57 * 48 kB cap -- so nothing here needs a bound of its own.
58 */
59
64template< typename T, const int LX, const int CHUNKS >
66 const T * __restrict__ u,
67 const T * __restrict__ dx,
68 const T * __restrict__ dy,
69 const T * __restrict__ dz,
70 const T * __restrict__ dxt,
71 const T * __restrict__ dyt,
72 const T * __restrict__ dzt,
73 const T * __restrict__ h1,
74 const T * __restrict__ g11,
75 const T * __restrict__ g22,
76 const T * __restrict__ g33,
77 const T * __restrict__ g12,
78 const T * __restrict__ g13,
79 const T * __restrict__ g23) {
80
84
88
93
94 const int e = blockIdx.x;
95 const int iii = threadIdx.x;
96 const int nchunks = (LX * LX * LX - 1)/CHUNKS + 1;
97
98 if (iii<LX*LX) {
99 shdx[iii] = dx[iii];
100 shdy[iii] = dy[iii];
101 shdz[iii] = dz[iii];
102 }
103
104 {
105 int i = iii;
106 while (i < LX * LX * LX){
107 shu[i] = u[i+e*LX*LX*LX];
108 i = i + CHUNKS;
109 }
110 }
111
113
114 if (iii<LX*LX){
115 shdxt[iii] = dxt[iii];
116 shdyt[iii] = dyt[iii];
117 shdzt[iii] = dzt[iii];
118 }
119
120 for (int n=0; n<nchunks; n++){
121 const int ijk = iii+n*CHUNKS;
122 const int jk = ijk/LX;
123 const int i = ijk-jk*LX;
124 const int k = jk/LX;
125 const int j = jk-k*LX;
126 if (i<LX && j<LX && k<LX && ijk < LX*LX*LX){
127 const T G00 = g11[ijk+e*LX*LX*LX];
128 const T G11 = g22[ijk+e*LX*LX*LX];
129 const T G22 = g33[ijk+e*LX*LX*LX];
130 const T G01 = g12[ijk+e*LX*LX*LX];
131 const T G02 = g13[ijk+e*LX*LX*LX];
132 const T G12 = g23[ijk+e*LX*LX*LX];
133 const T H1 = h1[ijk+e*LX*LX*LX];
134 T rtmp = 0.0;
135 T stmp = 0.0;
136 T ttmp = 0.0;
137#pragma unroll
138 for (int l = 0; l<LX; l++){
139 rtmp = rtmp + shdx[i+l*LX] * shu[l+j*LX+k*LX*LX];
140 stmp = stmp + shdy[j+l*LX] * shu[i+l*LX+k*LX*LX];
141 ttmp = ttmp + shdz[k+l*LX] * shu[i+j*LX+l*LX*LX];
142 }
143 shur[ijk] = H1 * (G00 * rtmp + G01 * stmp + G02 * ttmp);
144 shus[ijk] = H1 * (G01 * rtmp + G11 * stmp + G12 * ttmp);
145 shut[ijk] = H1 * (G02 * rtmp + G12 * stmp + G22 * ttmp);
146 }
147 }
148
150
151 for (int n=0; n<nchunks; n++){
152 const int ijk = iii+n*CHUNKS;
153 const int jk = ijk/LX;
154 const int k = jk/LX;
155 const int j = jk-k*LX;
156 const int i = ijk-jk*LX;
157 if (i<LX && j<LX && k<LX && ijk <LX*LX*LX){
158 T wijke = 0.0;
159#pragma unroll
160 for (int l = 0; l<LX; l++){
161 wijke = wijke
162 + shdxt[i+l*LX] * shur[l+j*LX+k*LX*LX]
163 + shdyt[j+l*LX] * shus[i+l*LX+k*LX*LX]
164 + shdzt[k+l*LX] * shut[i+j*LX+l*LX*LX];
165 }
166 w[ijk+e*LX*LX*LX] = wijke;
167 }
168 }
169}
170
171template< typename T, const int LX, const int EB >
174 const T * __restrict__ u,
185 const int nelv) {
186
187 /* Element independent, one copy per block */
188 __shared__ T shdx[LX * LX];
191
192 /* One slice per element in the block */
196
197 static_assert(sizeof(shdx) +
198 sizeof(shdy) +
199 sizeof(shdz) +
200 sizeof(shu) +
201 sizeof(shur) +
202 sizeof(shus)
204 "kstep block exceeds the shared memory budget");
205
209
210 /* Threads past the last element still have to reach the block wide
211 barriers below, so clamp their reads and drop their stores rather
212 than returning early. At EB == 1 the grid covers nelv exactly, so all
213 of this bookkeeping is constant folded and the kernel is exactly what
214 it was before blocking */
215 const int eb = (EB == 1) ? 0 : threadIdx.z;
216 const int e_blk = blockIdx.x * EB + eb;
217 const bool active = (EB == 1) ? true : (e_blk < nelv);
218 const int e = active ? e_blk : (nelv - 1);
219 const int j = threadIdx.y;
220 const int i = threadIdx.x;
221 const int ij = i + j*LX;
222 const int sh = eb*LX*LX;
223 const int ele = e*LX*LX*LX;
224
225 if (eb == 0) {
226 shdx[ij] = dx[ij];
227 shdy[ij] = dy[ij];
228 shdz[ij] = dz[ij];
229 }
230
231#pragma unroll
232 for(int k = 0; k < LX; ++k){
233 ru[k] = u[ij + k*LX*LX + ele];
234 rw[k] = 0.0;
235 }
236
237
239#pragma unroll
240 for (int k = 0; k < LX; ++k){
241 const int ijk = ij + k*LX*LX;
242 const T G00 = g11[ijk+ele];
243 const T G11 = g22[ijk+ele];
244 const T G22 = g33[ijk+ele];
245 const T G01 = g12[ijk+ele];
246 const T G02 = g13[ijk+ele];
247 const T G12 = g23[ijk+ele];
248 const T H1 = h1[ijk+ele];
249 T ttmp = 0.0;
250 shu[sh + ij] = ru[k];
251#pragma unroll
252 for (int l = 0; l < LX; l++){
253 ttmp += shdz[k+l*LX] * ru[l];
254 }
256
257 T rtmp = 0.0;
258 T stmp = 0.0;
259#pragma unroll
260 for (int l = 0; l < LX; l++){
261 rtmp += shdx[i+l*LX] * shu[sh + l+j*LX];
262 stmp += shdy[j+l*LX] * shu[sh + i+l*LX];
263 }
264 shur[sh + ij] = H1
265 * (G00 * rtmp
266 + G01 * stmp
267 + G02 * ttmp);
268 shus[sh + ij] = H1
269 * (G01 * rtmp
270 + G11 * stmp
271 + G12 * ttmp);
272 rut = H1
273 * (G02 * rtmp
274 + G12 * stmp
275 + G22 * ttmp);
276
278
279 T wijke = 0.0;
280#pragma unroll
281 for (int l = 0; l < LX; l++){
282 wijke += shur[sh + l+j*LX] * shdx[l+i*LX];
283 rw[l] += rut * shdz[k+l*LX];
284 wijke += shus[sh + i+l*LX] * shdy[l + j*LX];
285 }
286 rw[k] += wijke;
287 }
288 if (active) {
289#pragma unroll
290 for (int k = 0; k < LX; ++k){
291 w[ij + k*LX*LX + ele] = rw[k];
292 }
293 }
294}
295
301template< typename T, const int LX, const int EB >
304 const T * __restrict__ u,
305 const T * __restrict__ dx,
306 const T * __restrict__ dy,
307 const T * __restrict__ dz,
308 const T * __restrict__ h1,
309 const T * __restrict__ g11,
310 const T * __restrict__ g22,
311 const T * __restrict__ g33,
312 const T * __restrict__ g12,
313 const T * __restrict__ g13,
314 const T * __restrict__ g23,
315 const int nelv) {
316
317 /* Element independent, one copy per block */
318 __shared__ T shdx[LX * (LX+1)];
319 __shared__ T shdy[LX * (LX+1)];
320 __shared__ T shdz[LX * (LX+1)];
321
322 /* One slice per element in the block */
323 __shared__ T shu[EB * LX * (LX+1)];
324 __shared__ T shur[EB * LX * LX]; // only accessed using fastest dimension
325 __shared__ T shus[EB * LX * (LX+1)];
326
327 static_assert(sizeof(shdx) +
328 sizeof(shdy) +
329 sizeof(shdz) +
330 sizeof(shu) +
331 sizeof(shur) +
332 sizeof(shus)
334 "kstep block exceeds the shared memory budget");
335
336 T ru[LX];
337 T rw[LX];
338 T rut;
339
340 /* At EB == 1 the grid covers nelv exactly, so the blocking bookkeeping is
341 constant folded away and the kernel is exactly what it was before */
342 const int eb = (EB == 1) ? 0 : threadIdx.z;
343 const int e_blk = blockIdx.x * EB + eb;
344 const bool active = (EB == 1) ? true : (e_blk < nelv);
345 const int e = active ? e_blk : (nelv - 1);
346 const int j = threadIdx.y;
347 const int i = threadIdx.x;
348 const int ij = i + j*LX;
349 const int ij_p = i + j*(LX+1);
350 const int sh = eb*LX*LX;
351 const int sh_p = eb*LX*(LX+1);
352 const int ele = e*LX*LX*LX;
353
354 if (eb == 0) {
355 shdx[ij_p] = dx[ij];
356 shdy[ij_p] = dy[ij];
357 shdz[ij_p] = dz[ij];
358 }
359
360#pragma unroll
361 for(int k = 0; k < LX; ++k){
362 ru[k] = u[ij + k*LX*LX + ele];
363 rw[k] = 0.0;
364 }
365
366
368#pragma unroll
369 for (int k = 0; k < LX; ++k){
370 const int ijk = ij + k*LX*LX;
371 const T G00 = g11[ijk+ele];
372 const T G11 = g22[ijk+ele];
373 const T G22 = g33[ijk+ele];
374 const T G01 = g12[ijk+ele];
375 const T G02 = g13[ijk+ele];
376 const T G12 = g23[ijk+ele];
377 const T H1 = h1[ijk+ele];
378 T ttmp = 0.0;
379 shu[sh_p + ij_p] = ru[k];
380#pragma unroll
381 for (int l = 0; l < LX; l++){
382 ttmp += shdz[k+l*(LX+1)] * ru[l];
383 }
385
386 T rtmp = 0.0;
387 T stmp = 0.0;
388#pragma unroll
389 for (int l = 0; l < LX; l++){
390 rtmp += shdx[i+l*(LX+1)] * shu[sh_p + l+j*(LX+1)];
391 stmp += shdy[j+l*(LX+1)] * shu[sh_p + i+l*(LX+1)];
392 }
393 shur[sh + ij] = H1
394 * (G00 * rtmp
395 + G01 * stmp
396 + G02 * ttmp);
397 shus[sh_p + ij_p] = H1
398 * (G01 * rtmp
399 + G11 * stmp
400 + G12 * ttmp);
401 rut = H1
402 * (G02 * rtmp
403 + G12 * stmp
404 + G22 * ttmp);
405
407
408 T wijke = 0.0;
409#pragma unroll
410 for (int l = 0; l < LX; l++){
411 wijke += shur[sh + l+j*LX] * shdx[l+i*(LX+1)];
412 rw[l] += rut * shdz[k+l*(LX+1)];
413 wijke += shus[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
414 }
415 rw[k] += wijke;
416 }
417 if (active) {
418#pragma unroll
419 for (int k = 0; k < LX; ++k){
420 w[ij + k*LX*LX + ele] = rw[k];
421 }
422 }
423}
424
425
438#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800) && (__CUDA_ARCH__ < 1000)
439
440template< const int LX, const int NW >
442void ax_helm_dmma_elem(double * __restrict__ w,
443 const double * __restrict__ u,
444 const double * __restrict__ dx,
445 const double * __restrict__ dy,
446 const double * __restrict__ dz,
447 const double * __restrict__ h1,
448 const double * __restrict__ g11,
449 const double * __restrict__ g22,
450 const double * __restrict__ g33,
451 const double * __restrict__ g12,
452 const double * __restrict__ g13,
453 const double * __restrict__ g23,
454 const int nelv) {
455
456 /* Element independent, one copy per block. Block diagonal when more than
457 one element is packed: one LX x LX copy of D per sub-cube */
459 __shared__ __align__(16) double shdy[DMMA_MAT];
460 __shared__ __align__(16) double shdz[DMMA_MAT];
461
462 /* The pack, padded to DMMA_P^3. shu carries the input and then the
463 output, shr, shs and sht the reference derivatives */
464 __shared__ __align__(16) double shu[DMMA_CUBE];
465 __shared__ __align__(16) double shr[DMMA_CUBE];
466 __shared__ __align__(16) double shs[DMMA_CUBE];
467 __shared__ __align__(16) double sht[DMMA_CUBE];
468
470 sizeof(shdy) +
471 sizeof(shdz) +
472 sizeof(shu) +
473 sizeof(shr) +
474 sizeof(shs) +
475 sizeof(sht)
478
479 /* Elements per sub-cube axis, and per cube, see the note in dmma_kernel.h.
480 At PPA == 1 the addressing is not left to constant fold -- dmma_pack is
481 specialised so the tail clamp and the guarded store are never emitted at
482 all, see the note there */
483 enum { PPA = (DMMA_P % LX == 0) ? (DMMA_P / LX) : 1,
484 PACK = PPA * PPA * PPA,
485 LX3 = LX * LX * LX,
486 NP = PACK * LX3 };
487
489
490 const int nthrds = 32 * NW;
491 const int tid = threadIdx.x;
492 const int wf = tid >> 5;
493 const int ebase = pack::ebase();
494
495 /* The padding has to be finite, see the note above. At LX == DMMA_P with
496 one element packed there is none and this is folded away */
497 if (PACK * LX3 < DMMA_CUBE) {
498 for (int p = tid; p < DMMA_CUBE; p += nthrds) {
499 shu[p] = 0.0;
500 }
501 }
502 if (LX < DMMA_P) {
503 for (int p = tid; p < DMMA_MAT; p += nthrds) {
504 shdx[p] = 0.0;
505 shdy[p] = 0.0;
506 shdz[p] = 0.0;
507 }
508 }
509 if (LX < DMMA_P) {
511 }
512
513 /* One copy of D per sub-cube, down the diagonal */
514 for (int p = tid; p < LX * LX; p += nthrds) {
515 const int i = p % LX;
516 const int l = p / LX;
517#pragma unroll
518 for (int b = 0; b < PPA; b++) {
519 const int m = (b * LX + i) + DMMA_P * (b * LX + l);
520 shdx[m] = dx[p];
521 shdy[m] = dy[p];
522 shdz[m] = dz[p];
523 }
524 }
525
526 for (int p = tid; p < NP; p += nthrds) {
527 const dmma_idx x = pack::map(p, ebase, nelv);
528
529 shu[x.c] = u[x.g];
530 }
531
533
537
539
540 for (int p = tid; p < NP; p += nthrds) {
541 const dmma_idx x = pack::map(p, ebase, nelv);
542 const int c = x.c;
543 const int gp = x.g;
544
545 const double G00 = g11[gp];
546 const double G11 = g22[gp];
547 const double G22 = g33[gp];
548 const double G01 = g12[gp];
549 const double G02 = g13[gp];
550 const double G12 = g23[gp];
551 const double H1 = h1[gp];
552
553 const double rtmp = shr[c];
554 const double stmp = shs[c];
555 const double ttmp = sht[c];
556
557 shr[c] = H1
558 * (G00 * rtmp
559 + G01 * stmp
560 + G02 * ttmp);
561 shs[c] = H1
562 * (G01 * rtmp
563 + G11 * stmp
564 + G12 * ttmp);
565 sht[c] = H1
566 * (G02 * rtmp
567 + G12 * stmp
568 + G22 * ttmp);
569 }
570
572
573 /* The result overwrites the staged input; the first contraction writes
574 every tile of the cube, so nothing has to be cleared first. The barriers
575 are needed because the j slab tiles of axis 2 span what every warp wrote
576 along axis 0 and 1 */
583
584 for (int p = tid; p < NP; p += nthrds) {
585 const dmma_idx x = pack::map(p, ebase, nelv);
586
587 if (x.live) {
588 w[x.g] = shu[x.c];
589 }
590 }
591}
592
593#endif // __CUDA_ARCH__ in [800, 1000)
594
595/*
596 * Compile-time dispatch onto the DMMA element kernel. The launch macros in
597 * ax_helm.cu are written for every LX the operator dispatches and for whatever
598 * `real` is, so every combination has to compile; the ones the strategy does
599 * not cover -- single precision, LX outside the supported range, a build
600 * without an fp64 tensor core arch -- resolve to this no-op. The autotuner
601 * never selects the strategy for them, so the no-op is unreachable at runtime,
602 * see dmma_lx_supported() and cuda_have_dmma() in dmma_kernel.h.
603 */
604template< typename T, const int LX, const int NW >
607 const T * __restrict__,
608 const T * __restrict__,
609 const T * __restrict__,
610 const T * __restrict__,
611 const T * __restrict__,
612 const T * __restrict__,
613 const T * __restrict__,
614 const T * __restrict__,
615 const T * __restrict__,
616 const T * __restrict__,
617 const T * __restrict__,
618 const int) { }
619};
620
621#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800) && (__CUDA_ARCH__ < 1000)
622
623/* Keep in sync with dmma_lx_supported() in dmma_kernel.h */
624#define NEKO_AX_HELM_DMMA_DISPATCH(LXV) \
625 template< const int NW > \
626 struct ax_helm_dmma_dispatch< double, LXV, NW > { \
627 __device__ static void run(double * __restrict__ w, \
628 const double * __restrict__ u, \
629 const double * __restrict__ dx, \
630 const double * __restrict__ dy, \
631 const double * __restrict__ dz, \
632 const double * __restrict__ h1, \
633 const double * __restrict__ g11, \
634 const double * __restrict__ g22, \
635 const double * __restrict__ g33, \
636 const double * __restrict__ g12, \
637 const double * __restrict__ g13, \
638 const double * __restrict__ g23, \
639 const int nelv) { \
640 ax_helm_dmma_elem< LXV, NW >(w, u, dx, dy, dz, h1, \
641 g11, g22, g33, g12, g13, g23, nelv); \
642 } \
643 }
644
652
653#endif // __CUDA_ARCH__ in [800, 1000)
654
655template< typename T, const int LX, const int NW >
658 const T * __restrict__ u,
659 const T * __restrict__ dx,
660 const T * __restrict__ dy,
661 const T * __restrict__ dz,
662 const T * __restrict__ h1,
663 const T * __restrict__ g11,
664 const T * __restrict__ g22,
665 const T * __restrict__ g33,
666 const T * __restrict__ g12,
667 const T * __restrict__ g13,
668 const T * __restrict__ g23,
669 const int nelv) {
670
672 g11, g22, g33, g12, g13, g23, nelv);
673}
674
695#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
696 (__CUDA_ARCH__ < 1000) && NEKO_TMA_TOOLKIT
697
698template< const int LX, const int NW >
701 const double * __restrict__ u,
702 const double * __restrict__ dx,
703 const double * __restrict__ dy,
704 const double * __restrict__ dz,
705 const double * __restrict__ h1,
706 const double * __restrict__ g11,
707 const double * __restrict__ g22,
708 const double * __restrict__ g33,
709 const double * __restrict__ g12,
710 const double * __restrict__ g13,
711 const double * __restrict__ g23) {
712
713 /* A bulk copy needs 16 byte alignment at both ends; the cubes are given the
714 128 the tensor variants would want anyway, which costs nothing here since
715 every one of them is a whole number of 128 byte lines */
717 __shared__ __align__(128) double shdy[DMMA_MAT];
718 __shared__ __align__(128) double shdz[DMMA_MAT];
719
720 /* shu carries the input and then the output, shr, shs and sht the reference
721 derivatives */
722 __shared__ __align__(128) double shu[DMMA_CUBE];
723 __shared__ __align__(128) double shr[DMMA_CUBE];
724 __shared__ __align__(128) double shs[DMMA_CUBE];
725 __shared__ __align__(128) double sht[DMMA_CUBE];
726
727 /* h1, g11, g22, g33, g12, g13, g23 */
729
730 __shared__ __align__(8) unsigned long long bar_u;
731 __shared__ __align__(8) unsigned long long bar_g;
732
734 sizeof(shdy) +
735 sizeof(shdz) +
736 sizeof(shu) +
737 sizeof(shr) +
738 sizeof(shs) +
739 sizeof(sht) +
740 sizeof(shg) +
741 sizeof(bar_u) +
742 sizeof(bar_g)
745
746 /* Only lx == DMMA_P stages as a contiguous run of bytes, which is what a
747 bulk copy moves; see the scope note in dmma_tma_kernel.h. Keep in step
748 with dmma_tma_lx_supported() */
751
752 enum { CUBE_BYTES = DMMA_CUBE * (int) sizeof(double) };
753
754 const int nthrds = 32 * NW;
755 const int tid = threadIdx.x;
756 const int wf = tid >> 5;
757 const int ebase = blockIdx.x * DMMA_CUBE;
758
759 if (tid == 0) {
760 tma_barrier_init(&bar_u, 1);
761 tma_barrier_init(&bar_g, 1);
762 }
763
764 /* At LX == DMMA_P the derivative matrix fills the staged one exactly, and
765 there is no padding anywhere to zero */
766 for (int p = tid; p < DMMA_MAT; p += nthrds) {
767 shdx[p] = dx[p];
768 shdy[p] = dy[p];
769 shdz[p] = dz[p];
770 }
771
772 /* Both barriers initialised and both derivative matrices staged before
773 anyone waits on the one or contracts with the other */
775
776 if (tid == 0) {
777 tma_expect(&bar_u, CUBE_BYTES);
778 tma_load(shu, u + ebase, CUBE_BYTES, &bar_u);
779
780 tma_expect(&bar_g, DMMA_NG * CUBE_BYTES);
781 tma_load(shg[0], h1 + ebase, CUBE_BYTES, &bar_g);
782 tma_load(shg[1], g11 + ebase, CUBE_BYTES, &bar_g);
783 tma_load(shg[2], g22 + ebase, CUBE_BYTES, &bar_g);
784 tma_load(shg[3], g33 + ebase, CUBE_BYTES, &bar_g);
785 tma_load(shg[4], g12 + ebase, CUBE_BYTES, &bar_g);
786 tma_load(shg[5], g13 + ebase, CUBE_BYTES, &bar_g);
787 tma_load(shg[6], g23 + ebase, CUBE_BYTES, &bar_g);
788 }
789
790 /* u only. The seven factor cubes are still arriving */
791 tma_wait(&bar_u, 0);
792
796
798
799 tma_wait(&bar_g, 0);
800
801 for (int p = tid; p < DMMA_CUBE; p += nthrds) {
802 const double H1 = shg[0][p];
803 const double G00 = shg[1][p];
804 const double G11 = shg[2][p];
805 const double G22 = shg[3][p];
806 const double G01 = shg[4][p];
807 const double G02 = shg[5][p];
808 const double G12 = shg[6][p];
809
810 const double rtmp = shr[p];
811 const double stmp = shs[p];
812 const double ttmp = sht[p];
813
814 shr[p] = H1
815 * (G00 * rtmp
816 + G01 * stmp
817 + G02 * ttmp);
818 shs[p] = H1
819 * (G01 * rtmp
820 + G11 * stmp
821 + G12 * ttmp);
822 sht[p] = H1
823 * (G02 * rtmp
824 + G12 * stmp
825 + G22 * ttmp);
826 }
827
829
830 /* The result overwrites the staged input, exactly as in the scalar dmma
831 kernel; see the note there on why the barriers between these are needed */
837
838 /* The contractions wrote shu through the generic proxy and the bulk store
839 reads it through the async one, so the fence is needed on top of the
840 barrier; see tma_fence_shared() */
843
844 if (tid == 0) {
847 }
848
849 /* The store reads shu asynchronously, and shared memory lives only as long
850 as the block does: nothing may retire until it has been read out */
852}
853
854#endif // __CUDA_ARCH__ == sm_90 with a CUDA 12 toolkit
855
856/*
857 * Compile-time dispatch onto the TMA staged DMMA element kernel, see the note
858 * on ax_helm_dmma_dispatch above. The no-op covers everything the strategy
859 * does not: single precision, any lx but DMMA_P, a build without sm_90, and a
860 * toolkit older than CUDA 12.
861 */
862template< typename T, const int LX, const int NW >
865 const T * __restrict__,
866 const T * __restrict__,
867 const T * __restrict__,
868 const T * __restrict__,
869 const T * __restrict__,
870 const T * __restrict__,
871 const T * __restrict__,
872 const T * __restrict__,
873 const T * __restrict__,
874 const T * __restrict__,
875 const T * __restrict__) { }
876};
877
878#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
879 (__CUDA_ARCH__ < 1000) && NEKO_TMA_TOOLKIT
880
881/* Keep in sync with dmma_tma_lx_supported() in dmma_tma_kernel.h */
882#define NEKO_AX_HELM_DMMA_TMA_DISPATCH(LXV) \
883 template< const int NW > \
884 struct ax_helm_dmma_tma_dispatch< double, LXV, NW > { \
885 __device__ static void run(double * __restrict__ w, \
886 const double * __restrict__ u, \
887 const double * __restrict__ dx, \
888 const double * __restrict__ dy, \
889 const double * __restrict__ dz, \
890 const double * __restrict__ h1, \
891 const double * __restrict__ g11, \
892 const double * __restrict__ g22, \
893 const double * __restrict__ g33, \
894 const double * __restrict__ g12, \
895 const double * __restrict__ g13, \
896 const double * __restrict__ g23) { \
897 ax_helm_dmma_tma_elem< LXV, NW >(w, u, dx, dy, dz, h1, \
898 g11, g22, g33, g12, g13, g23); \
899 } \
900 }
901
903
904#endif // __CUDA_ARCH__ == sm_90 with a CUDA 12 toolkit
905
906template< typename T, const int LX, const int NW >
909 const T * __restrict__ u,
910 const T * __restrict__ dx,
911 const T * __restrict__ dy,
912 const T * __restrict__ dz,
913 const T * __restrict__ h1,
914 const T * __restrict__ g11,
915 const T * __restrict__ g22,
916 const T * __restrict__ g33,
917 const T * __restrict__ g12,
918 const T * __restrict__ g13,
919 const T * __restrict__ g23) {
920
922 g11, g22, g33, g12, g13, g23);
923}
924
925
926/*
927 * Vector versions
928 */
929
930template< typename T, const int LX, const int EB >
935 const T * __restrict__ u,
936 const T * __restrict__ v,
937 const T * __restrict__ w,
938 const T * __restrict__ dx,
939 const T * __restrict__ dy,
940 const T * __restrict__ dz,
941 const T * __restrict__ h1,
942 const T * __restrict__ g11,
943 const T * __restrict__ g22,
944 const T * __restrict__ g33,
945 const T * __restrict__ g12,
946 const T * __restrict__ g13,
947 const T * __restrict__ g23,
948 const int nelv) {
949
950 /* Element independent, one copy per block */
951 __shared__ T shdx[LX * LX];
952 __shared__ T shdy[LX * LX];
953 __shared__ T shdz[LX * LX];
954
955 /* One slice per element in the block */
956 __shared__ T shu[EB * LX * LX];
957 __shared__ T shur[EB * LX * LX];
958 __shared__ T shus[EB * LX * LX];
959
963
967
968 static_assert(sizeof(shdx) +
969 sizeof(shdy) +
970 sizeof(shdz) +
971 sizeof(shu) +
972 sizeof(shur) +
973 sizeof(shus) +
974 sizeof(shv) +
975 sizeof(shvr) +
976 sizeof(shvs) +
977 sizeof(shw) +
978 sizeof(shwr) +
979 sizeof(shws)
981 "kstep block exceeds the shared memory budget");
982
983 T ru[LX];
985 T rw[LX];
986
990
991 T rut;
994
995 /* At EB == 1 the grid covers nelv exactly, so the blocking bookkeeping is
996 constant folded away and the kernel is exactly what it was before */
997 const int eb = (EB == 1) ? 0 : threadIdx.z;
998 const int e_blk = blockIdx.x * EB + eb;
999 const bool active = (EB == 1) ? true : (e_blk < nelv);
1000 const int e = active ? e_blk : (nelv - 1);
1001 const int j = threadIdx.y;
1002 const int i = threadIdx.x;
1003 const int ij = i + j*LX;
1004 const int sh = eb*LX*LX;
1005 const int ele = e*LX*LX*LX;
1006
1007 if (eb == 0) {
1008 shdx[ij] = dx[ij];
1009 shdy[ij] = dy[ij];
1010 shdz[ij] = dz[ij];
1011 }
1012
1013#pragma unroll
1014 for(int k = 0; k < LX; ++k){
1015 ru[k] = u[ij + k*LX*LX + ele];
1016 ruw[k] = 0.0;
1017
1018 rv[k] = v[ij + k*LX*LX + ele];
1019 rvw[k] = 0.0;
1020
1021 rw[k] = w[ij + k*LX*LX + ele];
1022 rww[k] = 0.0;
1023 }
1024
1025
1026 __syncthreads();
1027#pragma unroll
1028 for (int k = 0; k < LX; ++k){
1029 const int ijk = ij + k*LX*LX;
1030 const T G00 = g11[ijk+ele];
1031 const T G11 = g22[ijk+ele];
1032 const T G22 = g33[ijk+ele];
1033 const T G01 = g12[ijk+ele];
1034 const T G02 = g13[ijk+ele];
1035 const T G12 = g23[ijk+ele];
1036 const T H1 = h1[ijk+ele];
1037 T uttmp = 0.0;
1038 T vttmp = 0.0;
1039 T wttmp = 0.0;
1040 shu[sh + ij] = ru[k];
1041 shv[sh + ij] = rv[k];
1042 shw[sh + ij] = rw[k];
1043#pragma unroll
1044 for (int l = 0; l < LX; l++){
1045 uttmp += shdz[k+l*LX] * ru[l];
1046 vttmp += shdz[k+l*LX] * rv[l];
1047 wttmp += shdz[k+l*LX] * rw[l];
1048 }
1049 __syncthreads();
1050
1051 T urtmp = 0.0;
1052 T ustmp = 0.0;
1053
1054 T vrtmp = 0.0;
1055 T vstmp = 0.0;
1056
1057 T wrtmp = 0.0;
1058 T wstmp = 0.0;
1059#pragma unroll
1060 for (int l = 0; l < LX; l++){
1061 urtmp += shdx[i+l*LX] * shu[sh + l+j*LX];
1062 ustmp += shdy[j+l*LX] * shu[sh + i+l*LX];
1063
1064 vrtmp += shdx[i+l*LX] * shv[sh + l+j*LX];
1065 vstmp += shdy[j+l*LX] * shv[sh + i+l*LX];
1066
1067 wrtmp += shdx[i+l*LX] * shw[sh + l+j*LX];
1068 wstmp += shdy[j+l*LX] * shw[sh + i+l*LX];
1069 }
1070
1071 shur[sh + ij] = H1
1072 * (G00 * urtmp
1073 + G01 * ustmp
1074 + G02 * uttmp);
1075 shus[sh + ij] = H1
1076 * (G01 * urtmp
1077 + G11 * ustmp
1078 + G12 * uttmp);
1079 rut = H1
1080 * (G02 * urtmp
1081 + G12 * ustmp
1082 + G22 * uttmp);
1083
1084 shvr[sh + ij] = H1
1085 * (G00 * vrtmp
1086 + G01 * vstmp
1087 + G02 * vttmp);
1088 shvs[sh + ij] = H1
1089 * (G01 * vrtmp
1090 + G11 * vstmp
1091 + G12 * vttmp);
1092 rvt = H1
1093 * (G02 * vrtmp
1094 + G12 * vstmp
1095 + G22 * vttmp);
1096
1097 shwr[sh + ij] = H1
1098 * (G00 * wrtmp
1099 + G01 * wstmp
1100 + G02 * wttmp);
1101 shws[sh + ij] = H1
1102 * (G01 * wrtmp
1103 + G11 * wstmp
1104 + G12 * wttmp);
1105 rwt = H1
1106 * (G02 * wrtmp
1107 + G12 * wstmp
1108 + G22 * wttmp);
1109
1110 __syncthreads();
1111
1112 T uwijke = 0.0;
1113 T vwijke = 0.0;
1114 T wwijke = 0.0;
1115#pragma unroll
1116 for (int l = 0; l < LX; l++){
1117 uwijke += shur[sh + l+j*LX] * shdx[l+i*LX];
1118 ruw[l] += rut * shdz[k+l*LX];
1119 uwijke += shus[sh + i+l*LX] * shdy[l + j*LX];
1120
1121 vwijke += shvr[sh + l+j*LX] * shdx[l+i*LX];
1122 rvw[l] += rvt * shdz[k+l*LX];
1123 vwijke += shvs[sh + i+l*LX] * shdy[l + j*LX];
1124
1125 wwijke += shwr[sh + l+j*LX] * shdx[l+i*LX];
1126 rww[l] += rwt * shdz[k+l*LX];
1127 wwijke += shws[sh + i+l*LX] * shdy[l + j*LX];
1128 }
1129 ruw[k] += uwijke;
1130 rvw[k] += vwijke;
1131 rww[k] += wwijke;
1132 }
1133 if (active) {
1134#pragma unroll
1135 for (int k = 0; k < LX; ++k){
1136 au[ij + k*LX*LX + ele] = ruw[k];
1137 av[ij + k*LX*LX + ele] = rvw[k];
1138 aw[ij + k*LX*LX + ele] = rww[k];
1139 }
1140 }
1141}
1142
1143template< typename T, const int LX, const int EB >
1146 T * __restrict__ av,
1147 T * __restrict__ aw,
1148 const T * __restrict__ u,
1149 const T * __restrict__ v,
1150 const T * __restrict__ w,
1151 const T * __restrict__ dx,
1152 const T * __restrict__ dy,
1153 const T * __restrict__ dz,
1154 const T * __restrict__ h1,
1155 const T * __restrict__ g11,
1156 const T * __restrict__ g22,
1157 const T * __restrict__ g33,
1158 const T * __restrict__ g12,
1159 const T * __restrict__ g13,
1160 const T * __restrict__ g23,
1161 const int nelv) {
1162
1163 /* Element independent, one copy per block */
1164 __shared__ T shdx[LX * (LX+1)];
1165 __shared__ T shdy[LX * (LX+1)];
1166 __shared__ T shdz[LX * (LX+1)];
1167
1168 /* One slice per element in the block */
1169 __shared__ T shu[EB * LX * (LX+1)];
1170 __shared__ T shur[EB * LX * LX];
1171 __shared__ T shus[EB * LX * (LX+1)];
1172
1173 __shared__ T shv[EB * LX * (LX+1)];
1174 __shared__ T shvr[EB * LX * LX];
1175 __shared__ T shvs[EB * LX * (LX+1)];
1176
1177 __shared__ T shw[EB * LX * (LX+1)];
1178 __shared__ T shwr[EB * LX * LX];
1179 __shared__ T shws[EB * LX * (LX+1)];
1180
1181 static_assert(sizeof(shdx) +
1182 sizeof(shdy) +
1183 sizeof(shdz) +
1184 sizeof(shu) +
1185 sizeof(shur) +
1186 sizeof(shus) +
1187 sizeof(shv) +
1188 sizeof(shvr) +
1189 sizeof(shvs) +
1190 sizeof(shw) +
1191 sizeof(shwr) +
1192 sizeof(shws)
1194 "kstep block exceeds the shared memory budget");
1195
1196 T ru[LX];
1197 T rv[LX];
1198 T rw[LX];
1199
1200 T ruw[LX];
1201 T rvw[LX];
1202 T rww[LX];
1203
1204 T rut;
1205 T rvt;
1206 T rwt;
1207
1208 /* At EB == 1 the grid covers nelv exactly, so the blocking bookkeeping is
1209 constant folded away and the kernel is exactly what it was before */
1210 const int eb = (EB == 1) ? 0 : threadIdx.z;
1211 const int e_blk = blockIdx.x * EB + eb;
1212 const bool active = (EB == 1) ? true : (e_blk < nelv);
1213 const int e = active ? e_blk : (nelv - 1);
1214 const int j = threadIdx.y;
1215 const int i = threadIdx.x;
1216 const int ij = i + j*LX;
1217 const int ij_p = i + j*(LX+1);
1218 const int sh = eb*LX*LX;
1219 const int sh_p = eb*LX*(LX+1);
1220 const int ele = e*LX*LX*LX;
1221
1222 if (eb == 0) {
1223 shdx[ij_p] = dx[ij];
1224 shdy[ij_p] = dy[ij];
1225 shdz[ij_p] = dz[ij];
1226 }
1227
1228#pragma unroll
1229 for(int k = 0; k < LX; ++k){
1230 ru[k] = u[ij + k*LX*LX + ele];
1231 ruw[k] = 0.0;
1232
1233 rv[k] = v[ij + k*LX*LX + ele];
1234 rvw[k] = 0.0;
1235
1236 rw[k] = w[ij + k*LX*LX + ele];
1237 rww[k] = 0.0;
1238 }
1239
1240
1241 __syncthreads();
1242#pragma unroll
1243 for (int k = 0; k < LX; ++k){
1244 const int ijk = ij + k*LX*LX;
1245 const T G00 = g11[ijk+ele];
1246 const T G11 = g22[ijk+ele];
1247 const T G22 = g33[ijk+ele];
1248 const T G01 = g12[ijk+ele];
1249 const T G02 = g13[ijk+ele];
1250 const T G12 = g23[ijk+ele];
1251 const T H1 = h1[ijk+ele];
1252 T uttmp = 0.0;
1253 T vttmp = 0.0;
1254 T wttmp = 0.0;
1255 shu[sh_p + ij_p] = ru[k];
1256 shv[sh_p + ij_p] = rv[k];
1257 shw[sh_p + ij_p] = rw[k];
1258#pragma unroll
1259 for (int l = 0; l < LX; l++){
1260 uttmp += shdz[k+l*(LX+1)] * ru[l];
1261 vttmp += shdz[k+l*(LX+1)] * rv[l];
1262 wttmp += shdz[k+l*(LX+1)] * rw[l];
1263 }
1264 __syncthreads();
1265
1266 T urtmp = 0.0;
1267 T ustmp = 0.0;
1268
1269 T vrtmp = 0.0;
1270 T vstmp = 0.0;
1271
1272 T wrtmp = 0.0;
1273 T wstmp = 0.0;
1274#pragma unroll
1275 for (int l = 0; l < LX; l++){
1276 urtmp += shdx[i+l*(LX+1)] * shu[sh_p + l+j*(LX+1)];
1277 ustmp += shdy[j+l*(LX+1)] * shu[sh_p + i+l*(LX+1)];
1278
1279 vrtmp += shdx[i+l*(LX+1)] * shv[sh_p + l+j*(LX+1)];
1280 vstmp += shdy[j+l*(LX+1)] * shv[sh_p + i+l*(LX+1)];
1281
1282 wrtmp += shdx[i+l*(LX+1)] * shw[sh_p + l+j*(LX+1)];
1283 wstmp += shdy[j+l*(LX+1)] * shw[sh_p + i+l*(LX+1)];
1284 }
1285
1286 shur[sh + ij] = H1
1287 * (G00 * urtmp
1288 + G01 * ustmp
1289 + G02 * uttmp);
1290 shus[sh_p + ij_p] = H1
1291 * (G01 * urtmp
1292 + G11 * ustmp
1293 + G12 * uttmp);
1294 rut = H1
1295 * (G02 * urtmp
1296 + G12 * ustmp
1297 + G22 * uttmp);
1298
1299 shvr[sh + ij] = H1
1300 * (G00 * vrtmp
1301 + G01 * vstmp
1302 + G02 * vttmp);
1303 shvs[sh_p + ij_p] = H1
1304 * (G01 * vrtmp
1305 + G11 * vstmp
1306 + G12 * vttmp);
1307 rvt = H1
1308 * (G02 * vrtmp
1309 + G12 * vstmp
1310 + G22 * vttmp);
1311
1312 shwr[sh + ij] = H1
1313 * (G00 * wrtmp
1314 + G01 * wstmp
1315 + G02 * wttmp);
1316 shws[sh_p + ij_p] = H1
1317 * (G01 * wrtmp
1318 + G11 * wstmp
1319 + G12 * wttmp);
1320 rwt = H1
1321 * (G02 * wrtmp
1322 + G12 * wstmp
1323 + G22 * wttmp);
1324
1325 __syncthreads();
1326
1327 T uwijke = 0.0;
1328 T vwijke = 0.0;
1329 T wwijke = 0.0;
1330#pragma unroll
1331 for (int l = 0; l < LX; l++){
1332 uwijke += shur[sh + l+j*LX] * shdx[l+i*(LX+1)];
1333 ruw[l] += rut * shdz[k+l*(LX+1)];
1334 uwijke += shus[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
1335
1336 vwijke += shvr[sh + l+j*LX] * shdx[l+i*(LX+1)];
1337 rvw[l] += rvt * shdz[k+l*(LX+1)];
1338 vwijke += shvs[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
1339
1340 wwijke += shwr[sh + l+j*LX] * shdx[l+i*(LX+1)];
1341 rww[l] += rwt * shdz[k+l*(LX+1)];
1342 wwijke += shws[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
1343 }
1344 ruw[k] += uwijke;
1345 rvw[k] += vwijke;
1346 rww[k] += wwijke;
1347 }
1348 if (active) {
1349#pragma unroll
1350 for (int k = 0; k < LX; ++k){
1351 au[ij + k*LX*LX + ele] = ruw[k];
1352 av[ij + k*LX*LX + ele] = rvw[k];
1353 aw[ij + k*LX*LX + ele] = rww[k];
1354 }
1355 }
1356}
1357
1358
1385#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800) && (__CUDA_ARCH__ < 1000)
1386
1387template< const int LX, const int NW >
1390 double * __restrict__ av,
1391 double * __restrict__ aw,
1392 const double * __restrict__ u,
1393 const double * __restrict__ v,
1394 const double * __restrict__ w,
1395 const double * __restrict__ dx,
1396 const double * __restrict__ dy,
1397 const double * __restrict__ dz,
1398 const double * __restrict__ h1,
1399 const double * __restrict__ g11,
1400 const double * __restrict__ g22,
1401 const double * __restrict__ g33,
1402 const double * __restrict__ g12,
1403 const double * __restrict__ g13,
1404 const double * __restrict__ g23) {
1405
1406 /* Element independent, one copy per block */
1408 __shared__ __align__(16) double shdy[DMMA_MAT];
1409 __shared__ __align__(16) double shdz[DMMA_MAT];
1410
1411 /* One component at a time: shc carries it in and the result out, shr, shs
1412 and sht its reference derivatives */
1413 __shared__ __align__(16) double shc[DMMA_CUBE];
1414 __shared__ __align__(16) double shr[DMMA_CUBE];
1415 __shared__ __align__(16) double shs[DMMA_CUBE];
1416 __shared__ __align__(16) double sht[DMMA_CUBE];
1417
1419 sizeof(shdy) +
1420 sizeof(shdz) +
1421 sizeof(shc) +
1422 sizeof(shr) +
1423 sizeof(shs) +
1424 sizeof(sht)
1427
1428 enum { NTHRDS = 32 * NW,
1429 LX3 = LX * LX * LX,
1430 PPT = (LX3 + NTHRDS - 1) / NTHRDS };
1431
1432 const int tid = threadIdx.x;
1433 const int wf = tid >> 5;
1434 const int ele = blockIdx.x * LX3;
1435
1436 /* The geometric factors, read once and reused by all three components */
1437 double rG00[PPT], rG11[PPT], rG22[PPT];
1438 double rG01[PPT], rG02[PPT], rG12[PPT];
1439 double rH1[PPT];
1440 int rc[PPT];
1441
1442 /* The padding only has to be finite, see the note above. At LX == DMMA_P
1443 there is none and this is folded away */
1444 if (LX < DMMA_P) {
1445 for (int p = tid; p < DMMA_MAT; p += NTHRDS) {
1446 shdx[p] = 0.0;
1447 shdy[p] = 0.0;
1448 shdz[p] = 0.0;
1449 }
1450 for (int p = tid; p < DMMA_CUBE; p += NTHRDS) {
1451 shc[p] = 0.0;
1452 }
1453 __syncthreads();
1454 }
1455
1456 for (int p = tid; p < LX * LX; p += NTHRDS) {
1457 const int i = p % LX;
1458 const int l = p / LX;
1459 const int m = i + DMMA_P * l;
1460 shdx[m] = dx[p];
1461 shdy[m] = dy[p];
1462 shdz[m] = dz[p];
1463 }
1464
1465#pragma unroll
1466 for (int q = 0; q < PPT; q++) {
1467 const int p = tid + q * NTHRDS;
1468
1469 if (p < LX3) {
1470 const int i = p % LX;
1471 const int jk = p / LX;
1472 const int j = jk % LX;
1473 const int k = jk / LX;
1474 rc[q] = i + DMMA_SI * j + DMMA_SJ * k;
1475 rG00[q] = g11[p + ele];
1476 rG11[q] = g22[p + ele];
1477 rG22[q] = g33[p + ele];
1478 rG01[q] = g12[p + ele];
1479 rG02[q] = g13[p + ele];
1480 rG12[q] = g23[p + ele];
1481 rH1[q] = h1[p + ele];
1482 } else {
1483 rc[q] = 0;
1484 rG00[q] = 0.0;
1485 rG11[q] = 0.0;
1486 rG22[q] = 0.0;
1487 rG01[q] = 0.0;
1488 rG02[q] = 0.0;
1489 rG12[q] = 0.0;
1490 rH1[q] = 0.0;
1491 }
1492 }
1493
1494 __syncthreads();
1495
1496 const double * const cin[3] = { u, v, w };
1497 double * const cout[3] = { au, av, aw };
1498
1499#pragma unroll
1500 for (int c = 0; c < 3; c++) {
1501
1502 for (int p = tid; p < LX3; p += NTHRDS) {
1503 const int i = p % LX;
1504 const int jk = p / LX;
1505 const int j = jk % LX;
1506 const int k = jk / LX;
1507 shc[i + DMMA_SI * j + DMMA_SJ * k] = cin[c][p + ele];
1508 }
1509
1510 __syncthreads();
1511
1515
1516 __syncthreads();
1517
1518#pragma unroll
1519 for (int q = 0; q < PPT; q++) {
1520 const int p = tid + q * NTHRDS;
1521
1522 if (p < LX3) {
1523 const int idx = rc[q];
1524 const double rtmp = shr[idx];
1525 const double stmp = shs[idx];
1526 const double ttmp = sht[idx];
1527
1528 shr[idx] = rH1[q]
1529 * (rG00[q] * rtmp
1530 + rG01[q] * stmp
1531 + rG02[q] * ttmp);
1532 shs[idx] = rH1[q]
1533 * (rG01[q] * rtmp
1534 + rG11[q] * stmp
1535 + rG12[q] * ttmp);
1536 sht[idx] = rH1[q]
1537 * (rG02[q] * rtmp
1538 + rG12[q] * stmp
1539 + rG22[q] * ttmp);
1540 }
1541 }
1542
1543 __syncthreads();
1544
1546 __syncthreads();
1548 __syncthreads();
1550 __syncthreads();
1551
1552 for (int p = tid; p < LX3; p += NTHRDS) {
1553 const int i = p % LX;
1554 const int jk = p / LX;
1555 const int j = jk % LX;
1556 const int k = jk / LX;
1557 cout[c][p + ele] = shc[i + DMMA_SI * j + DMMA_SJ * k];
1558 }
1559
1560 /* shc is restaged by the next component */
1561 __syncthreads();
1562 }
1563}
1564
1565#endif // __CUDA_ARCH__ in [800, 1000)
1566
1567/*
1568 * Compile-time dispatch onto the vector DMMA element kernel, see the note on
1569 * ax_helm_dmma_dispatch above.
1570 */
1571template< typename T, const int LX, const int NW >
1574 T * __restrict__,
1575 T * __restrict__,
1576 const T * __restrict__,
1577 const T * __restrict__,
1578 const T * __restrict__,
1579 const T * __restrict__,
1580 const T * __restrict__,
1581 const T * __restrict__,
1582 const T * __restrict__,
1583 const T * __restrict__,
1584 const T * __restrict__,
1585 const T * __restrict__,
1586 const T * __restrict__,
1587 const T * __restrict__,
1588 const T * __restrict__) { }
1589};
1590
1591#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800) && (__CUDA_ARCH__ < 1000)
1592
1593/* Keep in sync with dmma_vector_lx_supported() in dmma_kernel.h, which is
1594 4 <= LX <= 8 and not the 2 <= LX <= 8 of the packed scalar kernel */
1595#define NEKO_AX_HELM_DMMA_VECTOR_DISPATCH(LXV) \
1596 template< const int NW > \
1597 struct ax_helm_dmma_vector_dispatch< double, LXV, NW > { \
1598 __device__ static void run(double * __restrict__ au, \
1599 double * __restrict__ av, \
1600 double * __restrict__ aw, \
1601 const double * __restrict__ u, \
1602 const double * __restrict__ v, \
1603 const double * __restrict__ w, \
1604 const double * __restrict__ dx, \
1605 const double * __restrict__ dy, \
1606 const double * __restrict__ dz, \
1607 const double * __restrict__ h1, \
1608 const double * __restrict__ g11, \
1609 const double * __restrict__ g22, \
1610 const double * __restrict__ g33, \
1611 const double * __restrict__ g12, \
1612 const double * __restrict__ g13, \
1613 const double * __restrict__ g23) { \
1614 ax_helm_dmma_vector_elem< LXV, NW >(au, av, aw, u, v, w, dx, dy, dz, h1, \
1615 g11, g22, g33, g12, g13, g23); \
1616 } \
1617 }
1618
1624
1625#endif // __CUDA_ARCH__ in [800, 1000)
1626
1627template< typename T, const int LX, const int NW >
1628__global__ void NEKO_EB_BOUNDS(32 * NW)
1630 T * __restrict__ av,
1631 T * __restrict__ aw,
1632 const T * __restrict__ u,
1633 const T * __restrict__ v,
1634 const T * __restrict__ w,
1635 const T * __restrict__ dx,
1636 const T * __restrict__ dy,
1637 const T * __restrict__ dz,
1638 const T * __restrict__ h1,
1639 const T * __restrict__ g11,
1640 const T * __restrict__ g22,
1641 const T * __restrict__ g33,
1642 const T * __restrict__ g12,
1643 const T * __restrict__ g13,
1644 const T * __restrict__ g23) {
1645
1647 dx, dy, dz, h1,
1648 g11, g22, g33,
1649 g12, g13, g23);
1650}
1651
1682#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
1683 (__CUDA_ARCH__ < 1000) && NEKO_TMA_TOOLKIT
1684
1685template< const int LX, const int NW >
1688 double * __restrict__ av,
1689 double * __restrict__ aw,
1690 const double * __restrict__ u,
1691 const double * __restrict__ v,
1692 const double * __restrict__ w,
1693 const double * __restrict__ dx,
1694 const double * __restrict__ dy,
1695 const double * __restrict__ dz,
1696 const double * __restrict__ h1,
1697 const double * __restrict__ g11,
1698 const double * __restrict__ g22,
1699 const double * __restrict__ g33,
1700 const double * __restrict__ g12,
1701 const double * __restrict__ g13,
1702 const double * __restrict__ g23) {
1703
1704 /* Element independent, one copy per block */
1706 __shared__ __align__(128) double shdy[DMMA_MAT];
1707 __shared__ __align__(128) double shdz[DMMA_MAT];
1708
1709 /* One component at a time: shc carries it in and the result out, shr, shs
1710 and sht its reference derivatives */
1711 __shared__ __align__(128) double shc[DMMA_CUBE];
1712 __shared__ __align__(128) double shr[DMMA_CUBE];
1713 __shared__ __align__(128) double shs[DMMA_CUBE];
1714 __shared__ __align__(128) double sht[DMMA_CUBE];
1715
1716 /* h1, g11, g22, g33, g12, g13, g23, shared by all three components */
1718
1719 __shared__ __align__(8) unsigned long long bar_c;
1720 __shared__ __align__(8) unsigned long long bar_g;
1721
1723 sizeof(shdy) +
1724 sizeof(shdz) +
1725 sizeof(shc) +
1726 sizeof(shr) +
1727 sizeof(shs) +
1728 sizeof(sht) +
1729 sizeof(shg) +
1730 sizeof(bar_c) +
1731 sizeof(bar_g)
1734
1735 /* Keep in step with dmma_tma_vector_lx_supported() */
1738
1739 enum { CUBE_BYTES = DMMA_CUBE * (int) sizeof(double) };
1740
1741 const int nthrds = 32 * NW;
1742 const int tid = threadIdx.x;
1743 const int wf = tid >> 5;
1744 const int ele = blockIdx.x * DMMA_CUBE;
1745
1746 if (tid == 0) {
1748 tma_barrier_init(&bar_g, 1);
1749 }
1750
1751 /* At LX == DMMA_P the derivative matrix fills the staged one exactly, and
1752 there is no padding anywhere to zero */
1753 for (int p = tid; p < DMMA_MAT; p += nthrds) {
1754 shdx[p] = dx[p];
1755 shdy[p] = dy[p];
1756 shdz[p] = dz[p];
1757 }
1758
1759 /* Both barriers initialised and both derivative matrices staged before
1760 anyone waits on the one or contracts with the other */
1761 __syncthreads();
1762
1763 /* Read once, outside the component loop, and waited on inside it at the
1764 first step that needs them */
1765 if (tid == 0) {
1766 tma_expect(&bar_g, DMMA_NG * CUBE_BYTES);
1767 tma_load(shg[0], h1 + ele, CUBE_BYTES, &bar_g);
1768 tma_load(shg[1], g11 + ele, CUBE_BYTES, &bar_g);
1769 tma_load(shg[2], g22 + ele, CUBE_BYTES, &bar_g);
1770 tma_load(shg[3], g33 + ele, CUBE_BYTES, &bar_g);
1771 tma_load(shg[4], g12 + ele, CUBE_BYTES, &bar_g);
1772 tma_load(shg[5], g13 + ele, CUBE_BYTES, &bar_g);
1773 tma_load(shg[6], g23 + ele, CUBE_BYTES, &bar_g);
1774 }
1775
1776 const double * const cin[3] = { u, v, w };
1777 double * const cout[3] = { au, av, aw };
1778
1779#pragma unroll
1780 for (int c = 0; c < 3; c++) {
1781
1782 if (tid == 0) {
1784 tma_load(shc, cin[c] + ele, CUBE_BYTES, &bar_c);
1785 }
1786
1787 /* bar_c is re-armed by every completion, so the parity of the phase each
1788 component's copy completes alternates. The __syncthreads() at the foot
1789 of the loop is what keeps the next component's arrive from racing a
1790 thread that has not yet observed this one */
1791 tma_wait(&bar_c, c & 1);
1792
1796
1797 __syncthreads();
1798
1799 /* Resident from here on; only the first component ever waits */
1800 if (c == 0) {
1801 tma_wait(&bar_g, 0);
1802 }
1803
1804 for (int p = tid; p < DMMA_CUBE; p += nthrds) {
1805 const double H1 = shg[0][p];
1806 const double G00 = shg[1][p];
1807 const double G11 = shg[2][p];
1808 const double G22 = shg[3][p];
1809 const double G01 = shg[4][p];
1810 const double G02 = shg[5][p];
1811 const double G12 = shg[6][p];
1812
1813 const double rtmp = shr[p];
1814 const double stmp = shs[p];
1815 const double ttmp = sht[p];
1816
1817 shr[p] = H1
1818 * (G00 * rtmp
1819 + G01 * stmp
1820 + G02 * ttmp);
1821 shs[p] = H1
1822 * (G01 * rtmp
1823 + G11 * stmp
1824 + G12 * ttmp);
1825 sht[p] = H1
1826 * (G02 * rtmp
1827 + G12 * stmp
1828 + G22 * ttmp);
1829 }
1830
1831 __syncthreads();
1832
1834 __syncthreads();
1836 __syncthreads();
1838
1839 /* The contractions wrote shc through the generic proxy and the bulk store
1840 reads it through the async one; see tma_fence_shared() */
1842 __syncthreads();
1843
1844 if (tid == 0) {
1847 }
1848
1849 /* shc is restaged by the next component, and nothing may retire while the
1850 store is still reading it */
1851 __syncthreads();
1852 }
1853}
1854
1855#endif // __CUDA_ARCH__ == sm_90 with a CUDA 12 toolkit
1856
1857/*
1858 * Compile-time dispatch onto the TMA staged vector DMMA element kernel, see
1859 * the note on ax_helm_dmma_tma_dispatch above.
1860 */
1861template< typename T, const int LX, const int NW >
1864 T * __restrict__,
1865 T * __restrict__,
1866 const T * __restrict__,
1867 const T * __restrict__,
1868 const T * __restrict__,
1869 const T * __restrict__,
1870 const T * __restrict__,
1871 const T * __restrict__,
1872 const T * __restrict__,
1873 const T * __restrict__,
1874 const T * __restrict__,
1875 const T * __restrict__,
1876 const T * __restrict__,
1877 const T * __restrict__,
1878 const T * __restrict__) { }
1879};
1880
1881#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
1882 (__CUDA_ARCH__ < 1000) && NEKO_TMA_TOOLKIT
1883
1884/* Keep in sync with dmma_tma_vector_lx_supported() in dmma_tma_kernel.h */
1885#define NEKO_AX_HELM_DMMA_TMA_VECTOR_DISPATCH(LXV) \
1886 template< const int NW > \
1887 struct ax_helm_dmma_tma_vector_dispatch< double, LXV, NW > { \
1888 __device__ static void run(double * __restrict__ au, \
1889 double * __restrict__ av, \
1890 double * __restrict__ aw, \
1891 const double * __restrict__ u, \
1892 const double * __restrict__ v, \
1893 const double * __restrict__ w, \
1894 const double * __restrict__ dx, \
1895 const double * __restrict__ dy, \
1896 const double * __restrict__ dz, \
1897 const double * __restrict__ h1, \
1898 const double * __restrict__ g11, \
1899 const double * __restrict__ g22, \
1900 const double * __restrict__ g33, \
1901 const double * __restrict__ g12, \
1902 const double * __restrict__ g13, \
1903 const double * __restrict__ g23) { \
1904 ax_helm_dmma_tma_vector_elem< LXV, NW >(au, av, aw, u, v, w, \
1905 dx, dy, dz, h1, \
1906 g11, g22, g33, \
1907 g12, g13, g23); \
1908 } \
1909 }
1910
1912
1913#endif // __CUDA_ARCH__ == sm_90 with a CUDA 12 toolkit
1914
1915template< typename T, const int LX, const int NW >
1916__global__ void NEKO_EB_BOUNDS(32 * NW)
1918 T * __restrict__ av,
1919 T * __restrict__ aw,
1920 const T * __restrict__ u,
1921 const T * __restrict__ v,
1922 const T * __restrict__ w,
1923 const T * __restrict__ dx,
1924 const T * __restrict__ dy,
1925 const T * __restrict__ dz,
1926 const T * __restrict__ h1,
1927 const T * __restrict__ g11,
1928 const T * __restrict__ g22,
1929 const T * __restrict__ g33,
1930 const T * __restrict__ g12,
1931 const T * __restrict__ g13,
1932 const T * __restrict__ g23) {
1933
1935 dx, dy, dz, h1,
1936 g11, g22, g33,
1937 g12, g13, g23);
1938}
1939
1940
1974#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
1975 (__CUDA_ARCH__ < 1000) && NEKO_TMA_TOOLKIT
1976
1977template< const int LX, const int NW >
1980 double * __restrict__ av,
1981 double * __restrict__ aw,
1982 const double * __restrict__ u,
1983 const double * __restrict__ v,
1984 const double * __restrict__ w,
1985 const double * __restrict__ dx,
1986 const double * __restrict__ dy,
1987 const double * __restrict__ dz,
1988 const double * __restrict__ h1,
1989 const double * __restrict__ g11,
1990 const double * __restrict__ g22,
1991 const double * __restrict__ g33,
1992 const double * __restrict__ g12,
1993 const double * __restrict__ g13,
1994 const double * __restrict__ g23) {
1995
1996 /* Keep in step with dmma_tma_batch_lx_supported() */
1997 static_assert(LX == DMMA_P,
1998 "the dmma tma batch variant stages whole cubes only");
1999
2003
2004 enum { CUBE_BYTES = DMMA_CUBE * (int) sizeof(double),
2005 /* v, w and the seven factors -- everything but the first cube */
2006 REST_BYTES = (DMMA_NG + 2) * CUBE_BYTES };
2007
2008 const int nthrds = 32 * NW;
2009 const int tid = threadIdx.x;
2010 const int wf = tid >> 5;
2011 const int ele = blockIdx.x * DMMA_CUBE;
2012
2013 if (tid == 0) {
2014 tma_barrier_init(&sm.bar_a, 1);
2015 tma_barrier_init(&sm.bar_b, 1);
2016 }
2017
2018 /* At LX == DMMA_P the derivative matrix fills the staged one exactly, and
2019 there is no padding anywhere to zero */
2020 for (int p = tid; p < DMMA_MAT; p += nthrds) {
2021 sm.dx[p] = dx[p];
2022 sm.dy[p] = dy[p];
2023 sm.dz[p] = dz[p];
2024 }
2025
2026 /* Both barriers initialised and both derivative matrices staged before
2027 anyone waits on the one or contracts with the other */
2028 __syncthreads();
2029
2030 /* The whole element, ten copies, one batch. u leads because it is the only
2031 one anything waits for before the contractions start */
2032 if (tid == 0) {
2033 tma_expect(&sm.bar_a, CUBE_BYTES);
2034 tma_load(sm.c[0], u + ele, CUBE_BYTES, &sm.bar_a);
2035
2036 tma_expect(&sm.bar_b, REST_BYTES);
2037 tma_load(sm.c[1], v + ele, CUBE_BYTES, &sm.bar_b);
2038 tma_load(sm.c[2], w + ele, CUBE_BYTES, &sm.bar_b);
2039 tma_load(sm.g[0], h1 + ele, CUBE_BYTES, &sm.bar_b);
2040 tma_load(sm.g[1], g11 + ele, CUBE_BYTES, &sm.bar_b);
2041 tma_load(sm.g[2], g22 + ele, CUBE_BYTES, &sm.bar_b);
2042 tma_load(sm.g[3], g33 + ele, CUBE_BYTES, &sm.bar_b);
2043 tma_load(sm.g[4], g12 + ele, CUBE_BYTES, &sm.bar_b);
2044 tma_load(sm.g[5], g13 + ele, CUBE_BYTES, &sm.bar_b);
2045 tma_load(sm.g[6], g23 + ele, CUBE_BYTES, &sm.bar_b);
2046 }
2047
2048 /* The first component only. The other nine copies are still arriving */
2049 tma_wait(&sm.bar_a, 0);
2050
2051 double * const cout[3] = { au, av, aw };
2052
2053#pragma unroll
2054 for (int c = 0; c < 3; c++) {
2055
2059
2060 __syncthreads();
2061
2062 /* Everything else has landed by here; components 1 and 2 never wait */
2063 if (c == 0) {
2064 tma_wait(&sm.bar_b, 0);
2065 }
2066
2067 for (int p = tid; p < DMMA_CUBE; p += nthrds) {
2068 const double H1 = sm.g[0][p];
2069 const double G00 = sm.g[1][p];
2070 const double G11 = sm.g[2][p];
2071 const double G22 = sm.g[3][p];
2072 const double G01 = sm.g[4][p];
2073 const double G02 = sm.g[5][p];
2074 const double G12 = sm.g[6][p];
2075
2076 const double rtmp = sm.r[p];
2077 const double stmp = sm.s[p];
2078 const double ttmp = sm.t[p];
2079
2080 sm.r[p] = H1
2081 * (G00 * rtmp
2082 + G01 * stmp
2083 + G02 * ttmp);
2084 sm.s[p] = H1
2085 * (G01 * rtmp
2086 + G11 * stmp
2087 + G12 * ttmp);
2088 sm.t[p] = H1
2089 * (G02 * rtmp
2090 + G12 * stmp
2091 + G22 * ttmp);
2092 }
2093
2094 __syncthreads();
2095
2096 /* The result overwrites the component's own staged input, which nothing
2097 reads again */
2099 __syncthreads();
2100 dmma_contract< 1, true, true, NW >(sm.c[c], sm.dy, sm.s, wf);
2101 __syncthreads();
2102 dmma_contract< 2, true, true, NW >(sm.c[c], sm.dz, sm.t, wf);
2103
2104 /* The contractions wrote sm.c[c] through the generic proxy and the bulk
2105 store reads it through the async one; see tma_fence_shared(). The
2106 barrier that follows also separates this component's last reads of
2107 r, s and t from the next one's writes to them */
2109 __syncthreads();
2110
2111 /* Issued and left uncommitted: the next component reads its own cube, so
2112 nothing here waits on this store. All three are committed together
2113 below */
2114 if (tid == 0) {
2115 tma_store(cout[c] + ele, sm.c[c], CUBE_BYTES);
2116 }
2117 }
2118
2119 /* Commit the three stores as one group and wait for them to have read their
2120 cubes out; shared memory lives only as long as the block does */
2121 if (tid == 0) {
2123 }
2124
2125 __syncthreads();
2126}
2127
2128#endif // __CUDA_ARCH__ == sm_90 with a CUDA 12 toolkit
2129
2130/*
2131 * Compile-time dispatch onto the batched TMA element kernel, see the note on
2132 * ax_helm_dmma_tma_dispatch above.
2133 */
2134template< typename T, const int LX, const int NW >
2137 T * __restrict__,
2138 T * __restrict__,
2139 const T * __restrict__,
2140 const T * __restrict__,
2141 const T * __restrict__,
2142 const T * __restrict__,
2143 const T * __restrict__,
2144 const T * __restrict__,
2145 const T * __restrict__,
2146 const T * __restrict__,
2147 const T * __restrict__,
2148 const T * __restrict__,
2149 const T * __restrict__,
2150 const T * __restrict__,
2151 const T * __restrict__) { }
2152};
2153
2154#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
2155 (__CUDA_ARCH__ < 1000) && NEKO_TMA_TOOLKIT
2156
2157/* Keep in sync with dmma_tma_batch_lx_supported() in dmma_tma_kernel.h */
2158#define NEKO_AX_HELM_DMMA_TMA_BATCH_DISPATCH(LXV) \
2159 template< const int NW > \
2160 struct ax_helm_dmma_tma_batch_dispatch< double, LXV, NW > { \
2161 __device__ static void run(double * __restrict__ au, \
2162 double * __restrict__ av, \
2163 double * __restrict__ aw, \
2164 const double * __restrict__ u, \
2165 const double * __restrict__ v, \
2166 const double * __restrict__ w, \
2167 const double * __restrict__ dx, \
2168 const double * __restrict__ dy, \
2169 const double * __restrict__ dz, \
2170 const double * __restrict__ h1, \
2171 const double * __restrict__ g11, \
2172 const double * __restrict__ g22, \
2173 const double * __restrict__ g33, \
2174 const double * __restrict__ g12, \
2175 const double * __restrict__ g13, \
2176 const double * __restrict__ g23) { \
2177 ax_helm_dmma_tma_batch_elem< LXV, NW >(au, av, aw, u, v, w, \
2178 dx, dy, dz, h1, \
2179 g11, g22, g33, \
2180 g12, g13, g23); \
2181 } \
2182 }
2183
2185
2186#endif // __CUDA_ARCH__ == sm_90 with a CUDA 12 toolkit
2187
2188template< typename T, const int LX, const int NW >
2189__global__ void NEKO_EB_BOUNDS(32 * NW)
2191 T * __restrict__ av,
2192 T * __restrict__ aw,
2193 const T * __restrict__ u,
2194 const T * __restrict__ v,
2195 const T * __restrict__ w,
2196 const T * __restrict__ dx,
2197 const T * __restrict__ dy,
2198 const T * __restrict__ dz,
2199 const T * __restrict__ h1,
2200 const T * __restrict__ g11,
2201 const T * __restrict__ g22,
2202 const T * __restrict__ g33,
2203 const T * __restrict__ g12,
2204 const T * __restrict__ g13,
2205 const T * __restrict__ g23) {
2206
2208 dx, dy, dz, h1,
2209 g11, g22, g33,
2210 g12, g13, g23);
2211}
2212
2213/*
2214 * Opt into the batched variant's dynamic allocation, once per specialisation.
2215 *
2216 * A block gets 48 kB of shared memory without asking; anything past that has
2217 * to be requested per kernel, and the carveout moved with it or the extra is
2218 * granted at the expense of nothing. Both are properties of the function, not
2219 * of the launch, so this is a function local static -- one flag per
2220 * <T, LX, NW> -- and the launch macro calls it ahead of every launch, where
2221 * after the first it is a single predictable branch.
2222 *
2223 * Returns false if the device refuses, which the tuner has already ruled out
2224 * via cuda_have_tma_batch(); the error is cleared rather than left to surface
2225 * against an unrelated CUDA_CHECK later.
2226 */
2227template< typename T, const int LX, const int NW >
2229{
2230 static int state = -1;
2231
2232 if (state < 0) {
2233 const void * const fn =
2238
2239 if (err == cudaSuccess) {
2243 }
2244 state = (err == cudaSuccess) ? 1 : 0;
2245 if (state == 0) {
2247 }
2248 }
2249 return state == 1;
2250}
2251
2252
2253template< typename T >
2255 T * __restrict__ av,
2256 T * __restrict__ aw,
2257 const T * __restrict__ u,
2258 const T * __restrict__ v,
2259 const T * __restrict__ w,
2260 const T * __restrict__ h2,
2261 const T * __restrict__ B,
2262 const int n) {
2263
2264 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
2265 const int str = blockDim.x * gridDim.x;
2266
2267 for (int i = idx; i < n; i += str) {
2268 au[i] = au[i] + h2[i] * B[i] * u[i];
2269 av[i] = av[i] + h2[i] * B[i] * v[i];
2270 aw[i] = aw[i] + h2[i] * B[i] * w[i];
2271 }
2272
2273}
2274#endif // __MATH_AX_HELM_KERNEL_H__
__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)
shdx[ij]
const bool active
const int ij_p
__shared__ T shus[EB *LX *LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g23
T rww[LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g22
__global__ void T *__restrict__ av
const int sh
static bool ax_helm_dmma_tma_batch_optin()
T ru[LX]
const int eb
__shared__ T shv[EB *LX *LX]
T rv[LX]
__shared__ T shwr[EB *LX *LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g13
__global__ void ax_helm_kernel_1d(T *__restrict__ w, const T *__restrict__ u, const T *__restrict__ dx, const T *__restrict__ dy, const T *__restrict__ dz, const T *__restrict__ dxt, const T *__restrict__ dyt, const T *__restrict__ dzt, const T *__restrict__ h1, const T *__restrict__ g11, const T *__restrict__ g22, const T *__restrict__ g33, const T *__restrict__ g12, const T *__restrict__ g13, const T *__restrict__ g23)
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const int nelv
const int sh_p
__shared__ T shur[EB *LX *LX]
const int i
__shared__ T shvs[EB *LX *LX]
const int ij
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g12
T rwt
T rw[LX]
__shared__ T shw[EB *LX *LX]
__shared__ T shws[EB *LX *LX]
__shared__ T shu[EB *LX *LX]
T rut
T ruw[LX]
const int e
__global__ void T *__restrict__ T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ w
const int e_blk
T rvt
T rvw[LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g33
__global__ void T *__restrict__ T *__restrict__ aw
__shared__ T shvr[EB *LX *LX]
__global__ void const T *__restrict__ u
const int ele
__global__ void const T *__restrict__ const T *__restrict__ dx
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dz
const int j
__shared__ T shdz[LX *LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ dy
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ h1
__syncthreads()
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g11
__global__ void T *__restrict__ T *__restrict__ const T *__restrict__ const T *__restrict__ v
__global__ void ax_helm_kernel_vector_part2(T *__restrict__ au, T *__restrict__ av, T *__restrict__ aw, const T *__restrict__ u, const T *__restrict__ v, const T *__restrict__ w, const T *__restrict__ h2, const T *__restrict__ B, const int n)
__shared__ T shdy[LX *LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dyt
__shared__ T shdzt[LX *LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dzt
__global__ void const T *__restrict__ x
__shared__ T shdyt[LX *LX]
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dxt
#define NEKO_EB_MAX_SMEM
Definition elem_block.h:60
#define NEKO_EB_BOUNDS(NT)
Definition elem_block.h:95
@ DMMA_SI
@ DMMA_CUBE
@ DMMA_SJ
@ DMMA_MAT
@ DMMA_P
#define DMMA_NG
#define NEKO_DMMA_TMA_BATCH_SMEM
Defines a vector.
Definition vector.f90:34
static __device__ void run(T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const int)
static __device__ void run(T *__restrict__, T *__restrict__, T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__)
static __device__ void run(T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__)
static __device__ void run(T *__restrict__, T *__restrict__, T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__)
static __device__ void run(T *__restrict__, T *__restrict__, T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__, const T *__restrict__)