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/*
5 Copyright (c) 2021-2024, The Neko Authors
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 * Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14
15 * Redistributions in binary form must reproduce the above
16 copyright notice, this list of conditions and the following
17 disclaimer in the documentation and/or other materials provided
18 with the distribution.
19
20 * Neither the name of the authors nor the names of its
21 contributors may be used to endorse or promote products derived
22 from this software without specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 POSSIBILITY OF SUCH DAMAGE.
36*/
37
38#include "elem_block.h"
39#include "mfma_kernel.h"
40
45template< typename T, const int LX, const int CHUNKS >
47 const T * __restrict__ u,
48 const T * __restrict__ dx,
49 const T * __restrict__ dy,
50 const T * __restrict__ dz,
51 const T * __restrict__ dxt,
52 const T * __restrict__ dyt,
53 const T * __restrict__ dzt,
54 const T * __restrict__ h1,
55 const T * __restrict__ g11,
56 const T * __restrict__ g22,
57 const T * __restrict__ g33,
58 const T * __restrict__ g12,
59 const T * __restrict__ g13,
60 const T * __restrict__ g23) {
61
65
69
74
75 const int e = blockIdx.x;
76 const int iii = threadIdx.x;
77 const int nchunks = (LX * LX * LX - 1)/CHUNKS + 1;
78
79 if (iii<LX*LX) {
80 shdx[iii] = dx[iii];
81 shdy[iii] = dy[iii];
82 shdz[iii] = dz[iii];
83 }
84
85 {
86 int i = iii;
87 while (i < LX * LX * LX){
88 shu[i] = u[i+e*LX*LX*LX];
89 i = i + CHUNKS;
90 }
91 }
92
94
95 if (iii<LX*LX){
96 shdxt[iii] = dxt[iii];
97 shdyt[iii] = dyt[iii];
98 shdzt[iii] = dzt[iii];
99 }
100
101 for (int n=0; n<nchunks; n++){
102 const int ijk = iii+n*CHUNKS;
103 const int jk = ijk/LX;
104 const int i = ijk-jk*LX;
105 const int k = jk/LX;
106 const int j = jk-k*LX;
107 if (i<LX && j<LX && k<LX && ijk < LX*LX*LX){
108 const T G00 = g11[ijk+e*LX*LX*LX];
109 const T G11 = g22[ijk+e*LX*LX*LX];
110 const T G22 = g33[ijk+e*LX*LX*LX];
111 const T G01 = g12[ijk+e*LX*LX*LX];
112 const T G02 = g13[ijk+e*LX*LX*LX];
113 const T G12 = g23[ijk+e*LX*LX*LX];
114 const T H1 = h1[ijk+e*LX*LX*LX];
115 T rtmp = 0.0;
116 T stmp = 0.0;
117 T ttmp = 0.0;
118#pragma unroll
119 for (int l = 0; l<LX; l++){
120 rtmp = rtmp + shdx[i+l*LX] * shu[l+j*LX+k*LX*LX];
121 stmp = stmp + shdy[j+l*LX] * shu[i+l*LX+k*LX*LX];
122 ttmp = ttmp + shdz[k+l*LX] * shu[i+j*LX+l*LX*LX];
123 }
124 shur[ijk] = H1 * (G00 * rtmp + G01 * stmp + G02 * ttmp);
125 shus[ijk] = H1 * (G01 * rtmp + G11 * stmp + G12 * ttmp);
126 shut[ijk] = H1 * (G02 * rtmp + G12 * stmp + G22 * ttmp);
127 }
128 }
129
131
132 for (int n=0; n<nchunks; n++){
133 const int ijk = iii+n*CHUNKS;
134 const int jk = ijk/LX;
135 const int k = jk/LX;
136 const int j = jk-k*LX;
137 const int i = ijk-jk*LX;
138 if (i<LX && j<LX && k<LX && ijk <LX*LX*LX){
139 T wijke = 0.0;
140#pragma unroll
141 for (int l = 0; l<LX; l++){
142 wijke = wijke
143 + shdxt[i+l*LX] * shur[l+j*LX+k*LX*LX]
144 + shdyt[j+l*LX] * shus[i+l*LX+k*LX*LX]
145 + shdzt[k+l*LX] * shut[i+j*LX+l*LX*LX];
146 }
147 w[ijk+e*LX*LX*LX] = wijke;
148 }
149 }
150}
151
152template< typename T, const int LX, const int EB >
155 const T * __restrict__ u,
166 const int nelv) {
167
168 /* Element independent, one copy per block */
169 __shared__ T shdx[LX * LX];
172
173 /* One slice per element in the block */
177
178 static_assert(sizeof(shdx) +
179 sizeof(shdy) +
180 sizeof(shdz) +
181 sizeof(shu) +
182 sizeof(shur) +
183 sizeof(shus)
185 "kstep block exceeds the LDS budget");
186
190
191 /* Threads past the last element still have to reach the block wide
192 barriers below, so clamp their reads and drop their stores rather
193 than returning early. At EB == 1 the grid covers nelv exactly, so all
194 of this bookkeeping is constant folded and the kernel is exactly what
195 it was before blocking */
196 const int eb = (EB == 1) ? 0 : threadIdx.z;
197 const int e_blk = blockIdx.x * EB + eb;
198 const bool active = (EB == 1) ? true : (e_blk < nelv);
199 const int e = active ? e_blk : (nelv - 1);
200 const int j = threadIdx.y;
201 const int i = threadIdx.x;
202 const int ij = i + j*LX;
203 const int sh = eb*LX*LX;
204 const int ele = e*LX*LX*LX;
205
206 if (eb == 0) {
207 shdx[ij] = dx[ij];
208 shdy[ij] = dy[ij];
209 shdz[ij] = dz[ij];
210 }
211
212#pragma unroll
213 for(int k = 0; k < LX; ++k){
214 ru[k] = u[ij + k*LX*LX + ele];
215 rw[k] = 0.0;
216 }
217
218
220#pragma unroll
221 for (int k = 0; k < LX; ++k){
222 const int ijk = ij + k*LX*LX;
223 const T G00 = g11[ijk+ele];
224 const T G11 = g22[ijk+ele];
225 const T G22 = g33[ijk+ele];
226 const T G01 = g12[ijk+ele];
227 const T G02 = g13[ijk+ele];
228 const T G12 = g23[ijk+ele];
229 const T H1 = h1[ijk+ele];
230 T ttmp = 0.0;
231 shu[sh + ij] = ru[k];
232#pragma unroll
233 for (int l = 0; l < LX; l++){
234 ttmp += shdz[k+l*LX] * ru[l];
235 }
237
238 T rtmp = 0.0;
239 T stmp = 0.0;
240#pragma unroll
241 for (int l = 0; l < LX; l++){
242 rtmp += shdx[i+l*LX] * shu[sh + l+j*LX];
243 stmp += shdy[j+l*LX] * shu[sh + i+l*LX];
244 }
245 shur[sh + ij] = H1
246 * (G00 * rtmp
247 + G01 * stmp
248 + G02 * ttmp);
249 shus[sh + ij] = H1
250 * (G01 * rtmp
251 + G11 * stmp
252 + G12 * ttmp);
253 rut = H1
254 * (G02 * rtmp
255 + G12 * stmp
256 + G22 * ttmp);
257
259
260 T wijke = 0.0;
261#pragma unroll
262 for (int l = 0; l < LX; l++){
263 wijke += shur[sh + l+j*LX] * shdx[l+i*LX];
264 rw[l] += rut * shdz[k+l*LX];
265 wijke += shus[sh + i+l*LX] * shdy[l + j*LX];
266 }
267 rw[k] += wijke;
268 }
269 if (active) {
270#pragma unroll
271 for (int k = 0; k < LX; ++k){
272 w[ij + k*LX*LX + ele] = rw[k];
273 }
274 }
275}
276
282template< typename T, const int LX, const int EB >
285 const T * __restrict__ u,
286 const T * __restrict__ dx,
287 const T * __restrict__ dy,
288 const T * __restrict__ dz,
289 const T * __restrict__ h1,
290 const T * __restrict__ g11,
291 const T * __restrict__ g22,
292 const T * __restrict__ g33,
293 const T * __restrict__ g12,
294 const T * __restrict__ g13,
295 const T * __restrict__ g23,
296 const int nelv) {
297
298 /* Element independent, one copy per block */
299 __shared__ T shdx[LX * (LX+1)];
300 __shared__ T shdy[LX * (LX+1)];
301 __shared__ T shdz[LX * (LX+1)];
302
303 /* One slice per element in the block */
304 __shared__ T shu[EB * LX * (LX+1)];
305 __shared__ T shur[EB * LX * LX]; // only accessed using fastest dimension
306 __shared__ T shus[EB * LX * (LX+1)];
307
308 static_assert(sizeof(shdx) +
309 sizeof(shdy) +
310 sizeof(shdz) +
311 sizeof(shu) +
312 sizeof(shur) +
313 sizeof(shus)
315 "kstep block exceeds the LDS budget");
316
317 T ru[LX];
318 T rw[LX];
319 T rut;
320
321 /* At EB == 1 the grid covers nelv exactly, so the blocking bookkeeping is
322 constant folded away and the kernel is exactly what it was before */
323 const int eb = (EB == 1) ? 0 : threadIdx.z;
324 const int e_blk = blockIdx.x * EB + eb;
325 const bool active = (EB == 1) ? true : (e_blk < nelv);
326 const int e = active ? e_blk : (nelv - 1);
327 const int j = threadIdx.y;
328 const int i = threadIdx.x;
329 const int ij = i + j*LX;
330 const int ij_p = i + j*(LX+1);
331 const int sh = eb*LX*LX;
332 const int sh_p = eb*LX*(LX+1);
333 const int ele = e*LX*LX*LX;
334
335 if (eb == 0) {
336 shdx[ij_p] = dx[ij];
337 shdy[ij_p] = dy[ij];
338 shdz[ij_p] = dz[ij];
339 }
340
341#pragma unroll
342 for(int k = 0; k < LX; ++k){
343 ru[k] = u[ij + k*LX*LX + ele];
344 rw[k] = 0.0;
345 }
346
347
349#pragma unroll
350 for (int k = 0; k < LX; ++k){
351 const int ijk = ij + k*LX*LX;
352 const T G00 = g11[ijk+ele];
353 const T G11 = g22[ijk+ele];
354 const T G22 = g33[ijk+ele];
355 const T G01 = g12[ijk+ele];
356 const T G02 = g13[ijk+ele];
357 const T G12 = g23[ijk+ele];
358 const T H1 = h1[ijk+ele];
359 T ttmp = 0.0;
360 shu[sh_p + ij_p] = ru[k];
361#pragma unroll
362 for (int l = 0; l < LX; l++){
363 ttmp += shdz[k+l*(LX+1)] * ru[l];
364 }
366
367 T rtmp = 0.0;
368 T stmp = 0.0;
369#pragma unroll
370 for (int l = 0; l < LX; l++){
371 rtmp += shdx[i+l*(LX+1)] * shu[sh_p + l+j*(LX+1)];
372 stmp += shdy[j+l*(LX+1)] * shu[sh_p + i+l*(LX+1)];
373 }
374 shur[sh + ij] = H1
375 * (G00 * rtmp
376 + G01 * stmp
377 + G02 * ttmp);
378 shus[sh_p + ij_p] = H1
379 * (G01 * rtmp
380 + G11 * stmp
381 + G12 * ttmp);
382 rut = H1
383 * (G02 * rtmp
384 + G12 * stmp
385 + G22 * ttmp);
386
388
389 T wijke = 0.0;
390#pragma unroll
391 for (int l = 0; l < LX; l++){
392 wijke += shur[sh + l+j*LX] * shdx[l+i*(LX+1)];
393 rw[l] += rut * shdz[k+l*(LX+1)];
394 wijke += shus[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
395 }
396 rw[k] += wijke;
397 }
398 if (active) {
399#pragma unroll
400 for (int k = 0; k < LX; ++k){
401 w[ij + k*LX*LX + ele] = rw[k];
402 }
403 }
404}
405
406
422#if defined(__gfx90a__) || defined(__gfx942__)
423
424/* Matrix-core axhelm for one element of order LX-1 (T = float or double).
425 *
426 * NWF cooperating wavefronts (blockDim = (64, NWF, 1)) process one element,
427 * sharing a single staged cube in LDS. The matrix-core column tiles are
428 * striped across the wavefronts (wf = threadIdx.y) via mfma_contract_sel, while
429 * the staging, geometry and write-back passes parallelise over all NWF*64
430 * threads (tid). The three accumulating divergence contractions stay separated
431 * by __syncthreads and each wavefront owns disjoint output columns, so the
432 * accumulation is race-free. NWF = 1 reproduces the single-wavefront kernel.
433 *
434 * mfma_contract_sel routes double precision through the batched 4x4x4 matrix
435 * core (full M-utilisation) and single precision through the 16x16x4 tile. */
436template< typename T, const int LX, const int NWF >
438 const T * __restrict__ u,
439 const T * __restrict__ dx,
440 const T * __restrict__ dy,
441 const T * __restrict__ dz,
442 const T * __restrict__ h1,
443 const T * __restrict__ g11,
444 const T * __restrict__ g22,
445 const T * __restrict__ g33,
446 const T * __restrict__ g12,
447 const T * __restrict__ g13,
448 const T * __restrict__ g23,
449 const int nelv) {
450 const int LX2 = LX * LX;
451 const int LX3 = LX * LX * LX;
452
453 /* NWF wavefronts per block, WPE of them cooperating on one element and the
454 block covering EB elements, see the note in mfma_kernel.h. At LX = 4 the
455 contraction offers one column group, so WPE is 1 and every wavefront gets
456 an element of its own rather than idling. */
457 enum { EB = NEKO_MFMA_EB_N(NWF, LX),
458 WPE = NWF / EB };
459 static_assert(WPE * EB == NWF,
460 "wavefronts per block must split evenly over the elements");
461
462 __shared__ T shdx[LX * LX];
463 __shared__ T shdy[LX * LX];
464 __shared__ T shdz[LX * LX];
465 __shared__ T shu[EB * LX * LX * LX]; // input u, later reused as output w
466 __shared__ T shr[EB * LX * LX * LX]; // d/dr -> Sr
467 __shared__ T shs[EB * LX * LX * LX]; // d/ds -> Ss
468 __shared__ T sht[EB * LX * LX * LX]; // d/dt -> St
469
470 static_assert(sizeof(shdx) + sizeof(shdy) + sizeof(shdz) +
471 sizeof(shu) + sizeof(shr) + sizeof(shs) + sizeof(sht)
473 "mfma block exceeds the shared memory budget");
474
475 const int lane = threadIdx.x; // 0..63 : lane within a wavefront
476 const int wf = threadIdx.y; // 0..NWF-1 : which wavefront
477 const int tid = wf * 64 + lane; // 0..NWF*64-1 : block-wide thread id
478 const int nthr = NWF * 64;
479
480 const int eb = wf / WPE; // which element this wavefront serves
481 const int sub = wf % WPE; // its rank among that element's waves
482 const int gtid = sub * 64 + lane; // thread id within the element group
483 const int gnthr = WPE * 64;
484
485 /* Threads past the last element still have to reach the block wide
486 barriers, so clamp their reads and drop their stores rather than
487 returning early. At EB == 1 the grid covers nelv exactly and this is
488 constant folded away */
489 const int e_blk = blockIdx.x * EB + eb;
490 const bool active = (EB == 1) ? true : (e_blk < nelv);
491 const int e = active ? e_blk : (nelv - 1);
492 const int ele = e * LX3;
493 const int sh = eb * LX3;
494
495 /* Reference derivative matrices, one copy shared by every element */
496 for (int p = tid; p < LX2; p += nthr) {
497 shdx[p] = dx[p];
498 shdy[p] = dy[p];
499 shdz[p] = dz[p];
500 }
501 /* Element-local field, staged by the wavefronts that own it */
502 for (int p = gtid; p < LX3; p += gnthr)
503 shu[sh + p] = u[p + ele];
504
506
507 /* Gradient: ur, us, ut in canonical i + LX*j + LX*LX*k layout. */
508 mfma_contract_sel<T, LX, 0, false, false, WPE>::run(shr + sh, shdx,
509 shu + sh, lane, sub);
510 mfma_contract_sel<T, LX, 1, false, false, WPE>::run(shs + sh, shdy,
511 shu + sh, lane, sub);
512 mfma_contract_sel<T, LX, 2, false, false, WPE>::run(sht + sh, shdz,
513 shu + sh, lane, sub);
514
516
517 /* Geometry (pointwise): (ur,us,ut) -> (Sr,Ss,St), reusing shr/shs/sht. */
518 for (int p = gtid; p < LX3; p += gnthr) {
519 const int gp = p + ele;
520 const T G00 = g11[gp], G11 = g22[gp], G22 = g33[gp];
521 const T G01 = g12[gp], G02 = g13[gp], G12 = g23[gp];
522 const T H1 = h1[gp];
523 const T rr = shr[sh + p], ss = shs[sh + p], tt = sht[sh + p];
524 shr[sh + p] = H1 * (G00 * rr + G01 * ss + G02 * tt);
525 shs[sh + p] = H1 * (G01 * rr + G11 * ss + G12 * tt);
526 sht[sh + p] = H1 * (G02 * rr + G12 * ss + G22 * tt);
527 }
528
530
531 /* Divergence: w = Dr^T Sr + Ds^T Ss + Dt^T St, accumulated in shu (= w). */
532 for (int p = gtid; p < LX3; p += gnthr)
533 shu[sh + p] = 0.0;
535
536 mfma_contract_sel<T, LX, 0, true, true, WPE>::run(shu + sh, shdx,
537 shr + sh, lane, sub);
539 mfma_contract_sel<T, LX, 1, true, true, WPE>::run(shu + sh, shdy,
540 shs + sh, lane, sub);
542 mfma_contract_sel<T, LX, 2, true, true, WPE>::run(shu + sh, shdz,
543 sht + sh, lane, sub);
545
546 if (active) {
547 for (int p = gtid; p < LX3; p += gnthr)
548 w[p + ele] = shu[sh + p];
549 }
550}
551#endif // __gfx90a__ || __gfx942__
552
553/*
554 * Compile-time dispatch onto the MFMA element kernel. The launch macros in
555 * ax_helm.hip are written for every LX the operator dispatches and for
556 * whatever `real` is, so every combination has to compile; the ones the
557 * strategy does not cover -- LX outside the supported range, a build without
558 * a matrix-core arch -- resolve to this no-op. The autotuner never selects
559 * the strategy for them, so the no-op is unreachable at runtime, see
560 * mfma_lx_supported() and hip_have_mfma() in mfma_kernel.h.
561 */
562template< typename T, const int LX, const int NWF >
564 __device__ static void run(T *, const T *, const T *, const T *, const T *,
565 const T *, const T *, const T *, const T *,
566 const T *, const T *, const T *, const int) {}
567};
568
569#if defined(__gfx90a__) || defined(__gfx942__)
570
571/* Keep in sync with mfma_lx_supported() in mfma_kernel.h */
572#define NEKO_AX_HELM_MFMA_DISPATCH(TYPE, LXV) \
573 template< const int NWF > \
574 struct ax_helm_mfma_dispatch< TYPE, LXV, NWF > { \
575 __device__ static void run(TYPE *w, const TYPE *u, \
576 const TYPE *dx, const TYPE *dy, \
577 const TYPE *dz, const TYPE *h1, \
578 const TYPE *g11, const TYPE *g22, \
579 const TYPE *g33, const TYPE *g12, \
580 const TYPE *g13, const TYPE *g23, \
581 const int nelv) { \
582 ax_helm_mfma_elem< TYPE, LXV, NWF >(w, u, dx, dy, dz, h1, \
583 g11, g22, g33, g12, g13, g23, \
584 nelv); \
585 } \
586 }
587
606
607#endif // __gfx90a__ || __gfx942__
608
609/*
610 * Note the bare __launch_bounds__ rather than NEKO_EB_BOUNDS: the kstep
611 * kernels ask for three waves per SIMD, and this kernel was validated on
612 * gfx90a/gfx942 without that constraint. Keep it byte-identical to the
613 * configuration that was confirmed on hardware.
614 */
615template< typename T, const int LX, const int NWF >
618 const T * __restrict__ u,
619 const T * __restrict__ dx,
620 const T * __restrict__ dy,
621 const T * __restrict__ dz,
622 const T * __restrict__ h1,
623 const T * __restrict__ g11,
624 const T * __restrict__ g22,
625 const T * __restrict__ g33,
626 const T * __restrict__ g12,
627 const T * __restrict__ g13,
628 const T * __restrict__ g23,
629 const int nelv) {
630
632 g11, g22, g33, g12, g13, g23, nelv);
633}
634
635/*
636 * Vector versions
637 */
638
639template< typename T, const int LX, const int EB >
644 const T * __restrict__ u,
645 const T * __restrict__ v,
646 const T * __restrict__ w,
647 const T * __restrict__ dx,
648 const T * __restrict__ dy,
649 const T * __restrict__ dz,
650 const T * __restrict__ h1,
651 const T * __restrict__ g11,
652 const T * __restrict__ g22,
653 const T * __restrict__ g33,
654 const T * __restrict__ g12,
655 const T * __restrict__ g13,
656 const T * __restrict__ g23,
657 const int nelv) {
658
659 /* Element independent, one copy per block */
660 __shared__ T shdx[LX * LX];
661 __shared__ T shdy[LX * LX];
662 __shared__ T shdz[LX * LX];
663
664 /* One slice per element in the block */
665 __shared__ T shu[EB * LX * LX];
666 __shared__ T shur[EB * LX * LX];
667 __shared__ T shus[EB * LX * LX];
668
672
676
677 static_assert(sizeof(shdx) +
678 sizeof(shdy) +
679 sizeof(shdz) +
680 sizeof(shu) +
681 sizeof(shur) +
682 sizeof(shus) +
683 sizeof(shv) +
684 sizeof(shvr) +
685 sizeof(shvs) +
686 sizeof(shw) +
687 sizeof(shwr) +
688 sizeof(shws)
690 "kstep block exceeds the LDS budget");
691
692 T ru[LX];
694 T rw[LX];
695
699
700 T rut;
703
704 /* At EB == 1 the grid covers nelv exactly, so the blocking bookkeeping is
705 constant folded away and the kernel is exactly what it was before */
706 const int eb = (EB == 1) ? 0 : threadIdx.z;
707 const int e_blk = blockIdx.x * EB + eb;
708 const bool active = (EB == 1) ? true : (e_blk < nelv);
709 const int e = active ? e_blk : (nelv - 1);
710 const int j = threadIdx.y;
711 const int i = threadIdx.x;
712 const int ij = i + j*LX;
713 const int sh = eb*LX*LX;
714 const int ele = e*LX*LX*LX;
715
716 if (eb == 0) {
717 shdx[ij] = dx[ij];
718 shdy[ij] = dy[ij];
719 shdz[ij] = dz[ij];
720 }
721
722#pragma unroll
723 for(int k = 0; k < LX; ++k){
724 ru[k] = u[ij + k*LX*LX + ele];
725 ruw[k] = 0.0;
726
727 rv[k] = v[ij + k*LX*LX + ele];
728 rvw[k] = 0.0;
729
730 rw[k] = w[ij + k*LX*LX + ele];
731 rww[k] = 0.0;
732 }
733
734
736#pragma unroll
737 for (int k = 0; k < LX; ++k){
738 const int ijk = ij + k*LX*LX;
739 const T G00 = g11[ijk+ele];
740 const T G11 = g22[ijk+ele];
741 const T G22 = g33[ijk+ele];
742 const T G01 = g12[ijk+ele];
743 const T G02 = g13[ijk+ele];
744 const T G12 = g23[ijk+ele];
745 const T H1 = h1[ijk+ele];
746 T uttmp = 0.0;
747 T vttmp = 0.0;
748 T wttmp = 0.0;
749 shu[sh + ij] = ru[k];
750 shv[sh + ij] = rv[k];
751 shw[sh + ij] = rw[k];
752#pragma unroll
753 for (int l = 0; l < LX; l++){
754 uttmp += shdz[k+l*LX] * ru[l];
755 vttmp += shdz[k+l*LX] * rv[l];
756 wttmp += shdz[k+l*LX] * rw[l];
757 }
759
760 T urtmp = 0.0;
761 T ustmp = 0.0;
762
763 T vrtmp = 0.0;
764 T vstmp = 0.0;
765
766 T wrtmp = 0.0;
767 T wstmp = 0.0;
768#pragma unroll
769 for (int l = 0; l < LX; l++){
770 urtmp += shdx[i+l*LX] * shu[sh + l+j*LX];
771 ustmp += shdy[j+l*LX] * shu[sh + i+l*LX];
772
773 vrtmp += shdx[i+l*LX] * shv[sh + l+j*LX];
774 vstmp += shdy[j+l*LX] * shv[sh + i+l*LX];
775
776 wrtmp += shdx[i+l*LX] * shw[sh + l+j*LX];
777 wstmp += shdy[j+l*LX] * shw[sh + i+l*LX];
778 }
779
780 shur[sh + ij] = H1
781 * (G00 * urtmp
782 + G01 * ustmp
783 + G02 * uttmp);
784 shus[sh + ij] = H1
785 * (G01 * urtmp
786 + G11 * ustmp
787 + G12 * uttmp);
788 rut = H1
789 * (G02 * urtmp
790 + G12 * ustmp
791 + G22 * uttmp);
792
793 shvr[sh + ij] = H1
794 * (G00 * vrtmp
795 + G01 * vstmp
796 + G02 * vttmp);
797 shvs[sh + ij] = H1
798 * (G01 * vrtmp
799 + G11 * vstmp
800 + G12 * vttmp);
801 rvt = H1
802 * (G02 * vrtmp
803 + G12 * vstmp
804 + G22 * vttmp);
805
806 shwr[sh + ij] = H1
807 * (G00 * wrtmp
808 + G01 * wstmp
809 + G02 * wttmp);
810 shws[sh + ij] = H1
811 * (G01 * wrtmp
812 + G11 * wstmp
813 + G12 * wttmp);
814 rwt = H1
815 * (G02 * wrtmp
816 + G12 * wstmp
817 + G22 * wttmp);
818
820
821 T uwijke = 0.0;
822 T vwijke = 0.0;
823 T wwijke = 0.0;
824#pragma unroll
825 for (int l = 0; l < LX; l++){
826 uwijke += shur[sh + l+j*LX] * shdx[l+i*LX];
827 ruw[l] += rut * shdz[k+l*LX];
828 uwijke += shus[sh + i+l*LX] * shdy[l + j*LX];
829
830 vwijke += shvr[sh + l+j*LX] * shdx[l+i*LX];
831 rvw[l] += rvt * shdz[k+l*LX];
832 vwijke += shvs[sh + i+l*LX] * shdy[l + j*LX];
833
834 wwijke += shwr[sh + l+j*LX] * shdx[l+i*LX];
835 rww[l] += rwt * shdz[k+l*LX];
836 wwijke += shws[sh + i+l*LX] * shdy[l + j*LX];
837 }
838 ruw[k] += uwijke;
839 rvw[k] += vwijke;
840 rww[k] += wwijke;
841 }
842 if (active) {
843#pragma unroll
844 for (int k = 0; k < LX; ++k){
845 au[ij + k*LX*LX + ele] = ruw[k];
846 av[ij + k*LX*LX + ele] = rvw[k];
847 aw[ij + k*LX*LX + ele] = rww[k];
848 }
849 }
850}
851
852template< typename T, const int LX, const int EB >
855 T * __restrict__ av,
856 T * __restrict__ aw,
857 const T * __restrict__ u,
858 const T * __restrict__ v,
859 const T * __restrict__ w,
860 const T * __restrict__ dx,
861 const T * __restrict__ dy,
862 const T * __restrict__ dz,
863 const T * __restrict__ h1,
864 const T * __restrict__ g11,
865 const T * __restrict__ g22,
866 const T * __restrict__ g33,
867 const T * __restrict__ g12,
868 const T * __restrict__ g13,
869 const T * __restrict__ g23,
870 const int nelv) {
871
872 /* Element independent, one copy per block */
873 __shared__ T shdx[LX * (LX+1)];
874 __shared__ T shdy[LX * (LX+1)];
875 __shared__ T shdz[LX * (LX+1)];
876
877 /* One slice per element in the block */
878 __shared__ T shu[EB * LX * (LX+1)];
879 __shared__ T shur[EB * LX * LX];
880 __shared__ T shus[EB * LX * (LX+1)];
881
882 __shared__ T shv[EB * LX * (LX+1)];
883 __shared__ T shvr[EB * LX * LX];
884 __shared__ T shvs[EB * LX * (LX+1)];
885
886 __shared__ T shw[EB * LX * (LX+1)];
887 __shared__ T shwr[EB * LX * LX];
888 __shared__ T shws[EB * LX * (LX+1)];
889
890 static_assert(sizeof(shdx) +
891 sizeof(shdy) +
892 sizeof(shdz) +
893 sizeof(shu) +
894 sizeof(shur) +
895 sizeof(shus) +
896 sizeof(shv) +
897 sizeof(shvr) +
898 sizeof(shvs) +
899 sizeof(shw) +
900 sizeof(shwr) +
901 sizeof(shws)
903 "kstep block exceeds the LDS budget");
904
905 T ru[LX];
906 T rv[LX];
907 T rw[LX];
908
909 T ruw[LX];
910 T rvw[LX];
911 T rww[LX];
912
913 T rut;
914 T rvt;
915 T rwt;
916
917 /* At EB == 1 the grid covers nelv exactly, so the blocking bookkeeping is
918 constant folded away and the kernel is exactly what it was before */
919 const int eb = (EB == 1) ? 0 : threadIdx.z;
920 const int e_blk = blockIdx.x * EB + eb;
921 const bool active = (EB == 1) ? true : (e_blk < nelv);
922 const int e = active ? e_blk : (nelv - 1);
923 const int j = threadIdx.y;
924 const int i = threadIdx.x;
925 const int ij = i + j*LX;
926 const int ij_p = i + j*(LX+1);
927 const int sh = eb*LX*LX;
928 const int sh_p = eb*LX*(LX+1);
929 const int ele = e*LX*LX*LX;
930
931 if (eb == 0) {
932 shdx[ij_p] = dx[ij];
933 shdy[ij_p] = dy[ij];
934 shdz[ij_p] = dz[ij];
935 }
936
937#pragma unroll
938 for(int k = 0; k < LX; ++k){
939 ru[k] = u[ij + k*LX*LX + ele];
940 ruw[k] = 0.0;
941
942 rv[k] = v[ij + k*LX*LX + ele];
943 rvw[k] = 0.0;
944
945 rw[k] = w[ij + k*LX*LX + ele];
946 rww[k] = 0.0;
947 }
948
949
951#pragma unroll
952 for (int k = 0; k < LX; ++k){
953 const int ijk = ij + k*LX*LX;
954 const T G00 = g11[ijk+ele];
955 const T G11 = g22[ijk+ele];
956 const T G22 = g33[ijk+ele];
957 const T G01 = g12[ijk+ele];
958 const T G02 = g13[ijk+ele];
959 const T G12 = g23[ijk+ele];
960 const T H1 = h1[ijk+ele];
961 T uttmp = 0.0;
962 T vttmp = 0.0;
963 T wttmp = 0.0;
964 shu[sh_p + ij_p] = ru[k];
965 shv[sh_p + ij_p] = rv[k];
966 shw[sh_p + ij_p] = rw[k];
967#pragma unroll
968 for (int l = 0; l < LX; l++){
969 uttmp += shdz[k+l*(LX+1)] * ru[l];
970 vttmp += shdz[k+l*(LX+1)] * rv[l];
971 wttmp += shdz[k+l*(LX+1)] * rw[l];
972 }
974
975 T urtmp = 0.0;
976 T ustmp = 0.0;
977
978 T vrtmp = 0.0;
979 T vstmp = 0.0;
980
981 T wrtmp = 0.0;
982 T wstmp = 0.0;
983#pragma unroll
984 for (int l = 0; l < LX; l++){
985 urtmp += shdx[i+l*(LX+1)] * shu[sh_p + l+j*(LX+1)];
986 ustmp += shdy[j+l*(LX+1)] * shu[sh_p + i+l*(LX+1)];
987
988 vrtmp += shdx[i+l*(LX+1)] * shv[sh_p + l+j*(LX+1)];
989 vstmp += shdy[j+l*(LX+1)] * shv[sh_p + i+l*(LX+1)];
990
991 wrtmp += shdx[i+l*(LX+1)] * shw[sh_p + l+j*(LX+1)];
992 wstmp += shdy[j+l*(LX+1)] * shw[sh_p + i+l*(LX+1)];
993 }
994
995 shur[sh + ij] = H1
996 * (G00 * urtmp
997 + G01 * ustmp
998 + G02 * uttmp);
999 shus[sh_p + ij_p] = H1
1000 * (G01 * urtmp
1001 + G11 * ustmp
1002 + G12 * uttmp);
1003 rut = H1
1004 * (G02 * urtmp
1005 + G12 * ustmp
1006 + G22 * uttmp);
1007
1008 shvr[sh + ij] = H1
1009 * (G00 * vrtmp
1010 + G01 * vstmp
1011 + G02 * vttmp);
1012 shvs[sh_p + ij_p] = H1
1013 * (G01 * vrtmp
1014 + G11 * vstmp
1015 + G12 * vttmp);
1016 rvt = H1
1017 * (G02 * vrtmp
1018 + G12 * vstmp
1019 + G22 * vttmp);
1020
1021 shwr[sh + ij] = H1
1022 * (G00 * wrtmp
1023 + G01 * wstmp
1024 + G02 * wttmp);
1025 shws[sh_p + ij_p] = H1
1026 * (G01 * wrtmp
1027 + G11 * wstmp
1028 + G12 * wttmp);
1029 rwt = H1
1030 * (G02 * wrtmp
1031 + G12 * wstmp
1032 + G22 * wttmp);
1033
1034 __syncthreads();
1035
1036 T uwijke = 0.0;
1037 T vwijke = 0.0;
1038 T wwijke = 0.0;
1039#pragma unroll
1040 for (int l = 0; l < LX; l++){
1041 uwijke += shur[sh + l+j*LX] * shdx[l+i*(LX+1)];
1042 ruw[l] += rut * shdz[k+l*(LX+1)];
1043 uwijke += shus[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
1044
1045 vwijke += shvr[sh + l+j*LX] * shdx[l+i*(LX+1)];
1046 rvw[l] += rvt * shdz[k+l*(LX+1)];
1047 vwijke += shvs[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
1048
1049 wwijke += shwr[sh + l+j*LX] * shdx[l+i*(LX+1)];
1050 rww[l] += rwt * shdz[k+l*(LX+1)];
1051 wwijke += shws[sh_p + i+l*(LX+1)] * shdy[l + j*(LX+1)];
1052 }
1053 ruw[k] += uwijke;
1054 rvw[k] += vwijke;
1055 rww[k] += wwijke;
1056 }
1057 if (active) {
1058#pragma unroll
1059 for (int k = 0; k < LX; ++k){
1060 au[ij + k*LX*LX + ele] = ruw[k];
1061 av[ij + k*LX*LX + ele] = rvw[k];
1062 aw[ij + k*LX*LX + ele] = rww[k];
1063 }
1064 }
1065}
1066
1067template< typename T >
1069 T * __restrict__ av,
1070 T * __restrict__ aw,
1071 const T * __restrict__ u,
1072 const T * __restrict__ v,
1073 const T * __restrict__ w,
1074 const T * __restrict__ h2,
1075 const T * __restrict__ B,
1076 const int n) {
1077
1078 const int idx = blockIdx.x * blockDim.x + threadIdx.x;
1079 const int str = blockDim.x * gridDim.x;
1080
1081 for (int i = idx; i < n; i += str) {
1082 au[i] = au[i] + h2[i] * B[i] * u[i];
1083 av[i] = av[i] + h2[i] * B[i] * v[i];
1084 aw[i] = aw[i] + h2[i] * B[i] * w[i];
1085 }
1086
1087}
1088#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
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
__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_BOUNDS(NT)
Definition elem_block.h:95
__global__ void __launch_bounds__((LX *LX *EB), 3) ax_helm_kernel_kstep(T *__restrict__ w
#define NEKO_EB_MAX_LDS
Definition elem_block.h:79
#define NEKO_MFMA_EB_N(NWF, LX)
static __device__ void run(T *, const T *, const T *, const T *, const T *, const T *, const T *, const T *, const T *, const T *, const T *, const T *, const int)