Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
dmma_tma_kernel.h
Go to the documentation of this file.
1#ifndef __MATH_DMMA_TMA_KERNEL_H__
2#define __MATH_DMMA_TMA_KERNEL_H__
3/*
4 Copyright (c) 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
92#include <stdlib.h>
93#include <stdint.h>
94#include <stddef.h>
95#include <cuda_runtime.h>
97#include "dmma_kernel.h"
98
99/* The geometric factor cubes staged per element: h1, g11, g22, g33, g12,
100 g13, g23, in that order */
101#define DMMA_NG 7
102
103/* opgrad stages the nine metric cubes drdx..dtdz. Its tenth factor, the
104 quadrature weight w3, is shared by every element and so is read straight
105 from global memory -- it is L2 resident after the first block and a bulk
106 copy of it per element would be pure waste */
107#define DMMA_NG_OPGRAD 9
108
109/* conv1 stages the same nine, plus the three convecting velocity components
110 and jacinv */
111#define DMMA_NG_CONV1 13
112
113/*
114 * cp.async.bulk is PTX ISA 8.0, which means CUDA 12.0. Compiling for sm_90 is
115 * not enough on its own: CUDA 11.8 targets sm_90 but its ptxas only speaks
116 * PTX 7.8 and would reject every asm block below, so the toolkit version is
117 * part of the guard rather than inferred from the arch.
118 */
119#if defined(CUDART_VERSION) && (CUDART_VERSION >= 12000)
120#define NEKO_TMA_TOOLKIT 1
121#else
122#define NEKO_TMA_TOOLKIT 0
123#endif
124
125/*
126 * Was sm_90 among the architectures this translation unit was compiled for?
127 * Same trap as dmma_arch_compiled() in dmma_kernel.h: a binary built for an
128 * older arch still runs on Hopper by JIT compiling its PTX, and the kernel
129 * body is guarded on __CUDA_ARCH__, so without this check a build for, say,
130 * sm_80 running on a GH200 would JIT the *no-op* body, time as free, win the
131 * tuner comparison and leave a stale w. Unlike the DMMA check this one is
132 * sm_90 exactly, not a range: sm_100 and later move the bulk copy semantics
133 * and would have to be measured before being allowed in.
134 */
135#ifndef NEKO_TMA_ARCH_COMPILED
136#if defined(__CUDA_ARCH_LIST__)
137static inline bool tma_arch_compiled()
138{
139 const int arch[] = { __CUDA_ARCH_LIST__ };
140
141 for (int i = 0; i < (int) (sizeof(arch)/sizeof(arch[0])); i++) {
142 if (arch[i] >= 900 && arch[i] < 1000) {
143 return true;
144 }
145 }
146 return false;
147}
148#else
149static inline bool tma_arch_compiled()
150{
151 return false;
152}
153#endif
154#else
155static inline bool tma_arch_compiled()
156{
157 return (NEKO_TMA_ARCH_COMPILED != 0);
158}
159#endif
160
165static inline bool cuda_have_tma()
166{
167#if NEKO_TMA_TOOLKIT
168 static int cached = -1;
169
170 if (cached < 0) {
171 int dev = 0;
173
174 if (!tma_arch_compiled()) {
175 cached = 0;
176 } else if (cudaGetDevice(&dev) == cudaSuccess &&
178 cached = (prop.major == 9) ? 1 : 0;
179 } else {
180 cached = 0;
181 }
182 }
183 return cached == 1;
184#else
185 return false;
186#endif
187}
188
198template< const int LX >
199static inline bool dmma_tma_lx_supported()
200{
201 return (sizeof(real) == 8) && (LX == DMMA_P);
202}
203
213template< const int LX >
215{
216 return (sizeof(real) == 8) && (LX == DMMA_P);
217}
218
228template< const int LX >
230{
231 return (sizeof(real) == 8) && (LX == DMMA_P);
232}
233
241template< const int LX >
243{
244 return (sizeof(real) == 8) && (LX == DMMA_P);
245}
246
247template< const int LX >
248static inline bool dmma_tma_conv1_lx_supported()
249{
250 return (sizeof(real) == 8) && (LX == DMMA_P);
251}
252
258template< const int LX >
259static inline bool dmma_tma_cdtp_lx_supported()
260{
261 return (sizeof(real) == 8) && (LX == DMMA_P);
262}
263
264/*
265 * The batched vector variant's block, as one struct in dynamic shared memory.
266 *
267 * Why a struct and why dynamic. The measurement that motivates this variant is
268 * that a bulk copy only pays for itself in company: the scalar kernel issues
269 * eight at once and wins at 20 warps per SM against 48, while the
270 * component-at-a-time vector kernel issues seven once and then two lone 4 kB
271 * copies, and loses at 20 warps against 16 -- with MORE occupancy than the
272 * kernel it loses to, which is what rules residency out as the cause. Putting
273 * every one of an element's thirteen cubes in shared at once takes the block
274 * to 54800 B, past the 48 kB a block gets without opting in, so the allocation
275 * has to be dynamic and the layout has to live somewhere. A struct puts it in
276 * one place and makes the launch size sizeof(), which cannot drift from it.
277 *
278 * Member order is the layout: every cube lands on a 4 kB boundary and the two
279 * mbarriers go last, so no padding is inserted and every bulk copy target is
280 * aligned far past the 16 bytes it needs. The asserts below hold that.
281 */
283 double c[3][DMMA_CUBE]; /* the three components, in and then out */
284 double r[DMMA_CUBE]; /* reference derivatives, reused by each */
285 double s[DMMA_CUBE]; /* component in turn */
286 double t[DMMA_CUBE];
287 double g[DMMA_NG][DMMA_CUBE]; /* h1, g11, g22, g33, g12, g13, g23 */
288 double dx[DMMA_MAT];
289 double dy[DMMA_MAT];
290 double dz[DMMA_MAT];
291 unsigned long long bar_a; /* the first component's cube */
292 unsigned long long bar_b; /* the other two, and the seven factors */
293};
294
295#define NEKO_DMMA_TMA_BATCH_SMEM ((int) sizeof(dmma_tma_batch_smem))
296
297/* 227 kB is the most a Hopper block can opt into; the runtime gate below
298 checks the device rather than trusting this */
299static_assert(sizeof(dmma_tma_batch_smem) <= 227 * 1024,
300 "dmma tma batch block exceeds the opt-in shared memory ceiling");
301static_assert(offsetof(dmma_tma_batch_smem, c) % 128 == 0 &&
302 offsetof(dmma_tma_batch_smem, g) % 128 == 0,
303 "dmma tma batch bulk copy targets must stay 128 byte aligned");
304
311static inline int cuda_tma_smem_optin()
312{
313#if NEKO_TMA_TOOLKIT
314 static int cached = -1;
315
316 if (cached < 0) {
317 int dev = 0;
318 int optin = 0;
319
320 if (!cuda_have_tma()) {
321 cached = 0;
322 } else if (cudaGetDevice(&dev) == cudaSuccess &&
325 dev) == cudaSuccess) {
326 cached = optin;
327 } else {
328 cached = 0;
329 }
330 }
331 return cached;
332#else
333 return 0;
334#endif
335}
336
337static inline bool cuda_have_tma_batch()
338{
340}
341
342/*
343 * opgrad's block, laid out the same way and for the same reason as
344 * dmma_tma_batch_smem above: thirteen cubes will not fit in the 48 kB a block
345 * gets without asking, so the allocation is dynamic and the layout lives in a
346 * struct whose sizeof() is the launch size.
347 *
348 * It comes to **exactly** the same 54800 B as the batched axhelm block -- both
349 * are thirteen cubes and three matrices -- so cuda_have_tma_batch()'s device
350 * gate covers this variant unchanged, and so does its four blocks per SM.
351 *
352 * The ten input copies are issued together, which is the arrangement the
353 * scalar axhelm variant won with and the component-at-a-time vector one lost
354 * with. The three outputs leave as ordinary coalesced stores rather than bulk
355 * ones: only 'u' is free by then, so bulk storing all three would either
356 * serialise on a single cube or cost a register hoist of rtmp/stmp/ttmp --
357 * and at 19% of the traffic the stores are not what this variant is for.
358 */
360 double u[DMMA_CUBE]; /* the input, dead after phase 1 */
361 double r[DMMA_CUBE]; /* the reference derivatives */
362 double s[DMMA_CUBE];
363 double t[DMMA_CUBE];
364 double g[DMMA_NG_OPGRAD][DMMA_CUBE]; /* drdx, dsdx, dtdx, drdy, ... dtdz */
365 double dx[DMMA_MAT];
366 double dy[DMMA_MAT];
367 double dz[DMMA_MAT];
368 unsigned long long bar_u; /* the input cube */
369 unsigned long long bar_g; /* the nine metric cubes */
370};
371
372#define NEKO_OPGRAD_TMA_SMEM ((int) sizeof(opgrad_tma_smem))
373
374/*
375 * conv1's block. Four more cubes than opgrad -- the three convecting velocity
376 * components and jacinv -- because every one of them is consumed at the same
377 * pointwise step and batching all fourteen copies is the whole point.
378 *
379 * 71184 B is three blocks per SM rather than opgrad's four, which is below the
380 * batched axhelm kernel's four and is the reason this one is a genuine
381 * question rather than an expected win. It has the best bytes per contraction
382 * of any operator in the tree (20480 at lx = 8, against axhelm's 6144), so
383 * there is more memory time here to hide the staging behind than anywhere
384 * else; whether that beats losing a block is what the tuner is for. Unlike
385 * opgrad there is a single output, so 'u' is free for it and the result does
386 * leave as one bulk store.
387 */
389 double u[DMMA_CUBE]; /* the input, then the output */
390 double r[DMMA_CUBE];
391 double s[DMMA_CUBE];
392 double t[DMMA_CUBE];
393 double g[DMMA_NG_CONV1][DMMA_CUBE]; /* vx, vy, vz, jacinv, drdx .. dtdz */
394 double dx[DMMA_MAT];
395 double dy[DMMA_MAT];
396 double dz[DMMA_MAT];
397 unsigned long long bar_u;
398 unsigned long long bar_g;
399};
400
401#define NEKO_CONV1_TMA_SMEM ((int) sizeof(conv1_tma_smem))
402
403static_assert(sizeof(opgrad_tma_smem) <= 227 * 1024 &&
404 sizeof(conv1_tma_smem) <= 227 * 1024,
405 "tma block exceeds the opt-in shared memory ceiling");
406static_assert(offsetof(opgrad_tma_smem, u) % 128 == 0 &&
407 offsetof(opgrad_tma_smem, g) % 128 == 0 &&
408 offsetof(conv1_tma_smem, u) % 128 == 0 &&
409 offsetof(conv1_tma_smem, g) % 128 == 0,
410 "tma bulk copy targets must stay 128 byte aligned");
411
417static inline bool cuda_have_tma_opgrad()
418{
420}
421
422static inline bool cuda_have_tma_conv1()
423{
425}
426
434template< const int LX >
435static inline bool dmma_tma_batch_lx_supported()
436{
437 return (sizeof(real) == 8) && (LX == DMMA_P);
438}
439
450static inline bool dmma_tma_ptr_aligned(const void *p)
451{
452 return ((((uintptr_t) p) & (uintptr_t) 15) == 0);
453}
454
455static inline bool dmma_tma_aligned(const void *w, const void *u,
456 const void *h1, const void *g11,
457 const void *g22, const void *g33,
458 const void *g12, const void *g13,
459 const void *g23)
460{
466}
467
468/* The vector operator's thirteen arrays, same check */
469static inline bool dmma_tma_vector_aligned(const void *au, const void *av,
470 const void *aw, const void *u,
471 const void *v, const void *w,
472 const void *h1, const void *g11,
473 const void *g22, const void *g33,
474 const void *g12, const void *g13,
475 const void *g23)
476{
477 return dmma_tma_aligned(au, u, h1, g11, g22, g33, g12, g13, g23) &&
480}
481
482/* The derivative operator's six arrays, same check */
483static inline bool dmma_tma_dudxyz_aligned(const void *du, const void *u,
484 const void *dr, const void *ds,
485 const void *dt, const void *jacinv)
486{
490}
491
492/* The nine metric cubes, which both opgrad and conv1 bulk copy */
493static inline bool dmma_tma_metrics_aligned(const void *drdx, const void *dsdx,
494 const void *dtdx, const void *drdy,
495 const void *dsdy, const void *dtdy,
496 const void *drdz, const void *dsdz,
497 const void *dtdz)
498{
504}
505
506/*
507 * opgrad copies ten arrays in and stores three with ordinary stores, so only
508 * the ten are checked -- an ordinary store has no alignment requirement beyond
509 * the type's, and w3 is never bulk copied either.
510 */
511static inline bool dmma_tma_opgrad_aligned(const void *u,
512 const void *drdx, const void *dsdx,
513 const void *dtdx, const void *drdy,
514 const void *dsdy, const void *dtdy,
515 const void *drdz, const void *dsdz,
516 const void *dtdz)
517{
518 return dmma_tma_ptr_aligned(u) &&
520 drdz, dsdz, dtdz);
521}
522
523/*
524 * cdtp copies four in and bulk stores its single output. w3 is shared by every
525 * element and read straight from global, so it is not among them.
526 */
527static inline bool dmma_tma_cdtp_aligned(const void *dtx, const void *x,
528 const void *dr, const void *ds,
529 const void *dt)
530{
534}
535
536/* conv1 copies fourteen in and bulk stores its single output, so all fifteen */
537static inline bool dmma_tma_conv1_aligned(const void *du, const void *u,
538 const void *vx, const void *vy,
539 const void *vz, const void *jacinv,
540 const void *drdx, const void *dsdx,
541 const void *dtdx, const void *drdy,
542 const void *dsdy, const void *dtdy,
543 const void *drdz, const void *dsdz,
544 const void *dtdz)
545{
550 drdz, dsdz, dtdz);
551}
552
553/* Forced candidate, used when NEKO_AUTOTUNE pins the DMMA_TMA variant. The
554 warps per block candidates are the DMMA ones, see NEKO_DMMA_NW() */
556{
557 const char *v = getenv("NEKO_DMMA_TMA_NW");
558 int c = (v != NULL) ? atoi(v) : 0;
559
561 c = 0;
562 }
563 return c;
564}
565
566/* Report every measured DMMA_TMA_BATCH candidate, see NEKO_TUNE_LOG_DMMA */
567#define NEKO_TUNE_LOG_DMMA_TMA_BATCH(LX, T5) \
568 do { \
569 for (int c = 0; c < NEKO_DMMA_CANDIDATES; c++) { \
570 if ((T5)[c] >= NEKO_TUNE_INIT) { continue; } \
571 char lbl_[16]; \
572 sprintf(lbl_, "TMAB %dw", NEKO_DMMA_NW(c)); \
573 sprintf(neko_log_buf, "%-13s: %9.2f us/call", lbl_, \
574 NEKO_TUNE_US((T5)[c], iters)); \
575 log_message(neko_log_buf); \
576 } \
577 } while (0)
578
579/* Report every measured DMMA_TMA candidate, see NEKO_TUNE_LOG_DMMA */
580#define NEKO_TUNE_LOG_DMMA_TMA(LX, T4) \
581 do { \
582 for (int c = 0; c < NEKO_DMMA_CANDIDATES; c++) { \
583 if ((T4)[c] >= NEKO_TUNE_INIT) { continue; } \
584 char lbl_[16]; \
585 sprintf(lbl_, "TMA %dw", NEKO_DMMA_NW(c)); \
586 sprintf(neko_log_buf, "%-13s: %9.2f us/call", lbl_, \
587 NEKO_TUNE_US((T4)[c], iters)); \
588 log_message(neko_log_buf); \
589 } \
590 } while (0)
591
592#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
593 (__CUDA_ARCH__ < 1000) && NEKO_TMA_TOOLKIT
594
595/*
596 * The mbarrier and bulk copy primitives, as inline PTX.
597 *
598 * Written out rather than reached through cuda::memcpy_async() and
599 * cuda::barrier because the point of the variant is to measure the TMA
600 * engine: libcu++ selects cp.async.bulk only when it can prove the size and
601 * alignment, and falls back to cp.async otherwise, which would still compile,
602 * still be correct, and quietly measure something else entirely.
603 *
604 * Every mbarrier and shared operand is addressed in the shared window, which
605 * is what __cvta_generic_to_shared() produces.
606 */
607
608__device__ __forceinline__ static unsigned int tma_smem(const void *p)
609{
610 return (unsigned int) __cvta_generic_to_shared(p);
611}
612
613/* And the global window, likewise. The bulk copies name the global state
614 space explicitly, so a generic address is not theirs to reinterpret: the
615 conversion is written out rather than left to the pointer happening to be
616 global already */
617__device__ __forceinline__ static unsigned long long tma_gmem(const void *p)
618{
619 return (unsigned long long) __cvta_generic_to_global(p);
620}
621
622/* 'count' is the number of arrivals the barrier waits for, one per producer
623 thread. Must be visible to every waiter before any of them waits, i.e. a
624 __syncthreads() has to separate this from the first tma_wait() */
625__device__ __forceinline__ static void tma_barrier_init(unsigned long long *bar,
626 const int count)
627{
628 asm volatile("mbarrier.init.shared::cta.b64 [%0], %1;"
629 :: "r"(tma_smem(bar)), "r"(count) : "memory");
630}
631
632/* Arrive, and declare how many bytes the copies about to be issued will
633 deliver. The barrier flips phase once the arrival has landed *and* the
634 completing copies have paid off the transaction count, so this has to
635 precede the copies it accounts for */
636__device__ __forceinline__ static void tma_expect(unsigned long long *bar,
637 const int bytes)
638{
639 asm volatile("mbarrier.arrive.expect_tx.shared::cta.b64 _, [%0], %1;"
640 :: "r"(tma_smem(bar)), "r"(bytes) : "memory");
641}
642
643/* One contiguous global -> shared bulk copy, completing on 'bar' */
644__device__ __forceinline__ static void tma_load(void *dst, const void *src,
645 const int bytes,
646 unsigned long long *bar)
647{
648 asm volatile("cp.async.bulk.shared::cluster.global"
649 ".mbarrier::complete_tx::bytes [%0], [%1], %2, [%3];"
650 :: "r"(tma_smem(dst)), "l"(tma_gmem(src)), "r"(bytes),
651 "r"(tma_smem(bar)) : "memory");
652}
653
654/* Spin until 'bar' completes the phase of parity 'phase'; the initial parity
655 is 0. try_wait in a C loop rather than a wait loop inside the asm because
656 this is inlined more than once per kernel and PTX labels are not renamed on
657 inlining, so an asm local label would be defined twice.
658
659 The volatile asm and its memory clobber are also what keep the compiler
660 from sinking the wait below the shared reads it guards; the hardware
661 ordering is the mbarrier's own. */
662__device__ __forceinline__ static void tma_wait(unsigned long long *bar,
663 const int phase)
664{
665 unsigned int done;
666
667 do {
668 asm volatile("{\n"
669 ".reg .pred p;\n"
670 "mbarrier.try_wait.parity.shared::cta.b64 p, [%1], %2;\n"
671 "selp.b32 %0, 1, 0, p;\n"
672 "}\n"
673 : "=r"(done) : "r"(tma_smem(bar)), "r"(phase) : "memory");
674 } while (done == 0);
675}
676
677/* Make this thread's ordinary shared memory writes visible to the async
678 proxy. Reads of shared memory by a bulk copy go through that proxy, and
679 ordinary stores are not ordered before them by __syncthreads() alone, so a
680 store issued without this can read stale shared memory. The load direction
681 needs no counterpart: there the mbarrier completion is what orders the
682 copy's writes before the ordinary reads that consume them. */
684{
685 asm volatile("fence.proxy.async.shared::cta;" ::: "memory");
686}
687
688/* One contiguous shared -> global bulk copy. Tracked by a bulk group rather
689 than an mbarrier: nothing reads the result back, it only has to have been
690 committed before the block releases its shared memory */
691__device__ __forceinline__ static void tma_store(void *dst, const void *src,
692 const int bytes)
693{
694 asm volatile("cp.async.bulk.global.shared::cta.bulk_group [%0], [%1], %2;"
695 :: "l"(tma_gmem(dst)), "r"(tma_smem(src)), "r"(bytes)
696 : "memory");
697}
698
699/* Commit the issued stores and wait for them to have read their source out of
700 shared memory. Only the issuing thread has a group to wait on, but no
701 thread may leave the block before it completes, hence the __syncthreads()
702 that follows this at the call site */
704{
705 asm volatile("cp.async.bulk.commit_group;" ::: "memory");
706 asm volatile("cp.async.bulk.wait_group 0;" ::: "memory");
707}
708
709#endif // __CUDA_ARCH__ == sm_90 with a CUDA 12 toolkit
710
711#endif // __MATH_DMMA_TMA_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)
__global__ void 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__ const T *__restrict__ const T *__restrict__ dtdy
__global__ void 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__ const T *__restrict__ dtdx
__global__ void 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__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dtdz
__global__ void T *__restrict__ T *__restrict__ aw
__global__ void T *__restrict__ T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ w
__global__ void 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__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ jacinv
const int i
__global__ void 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__ dsdz
__global__ void T *__restrict__ T *__restrict__ const T *__restrict__ u
__global__ void T *__restrict__ av
__global__ void 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__ drdz
__global__ void 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__ drdx
__global__ void 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__ dsdx
__global__ void T *__restrict__ T *__restrict__ const T *__restrict__ const T *__restrict__ v
__global__ void 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__ dsdy
__global__ void 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__ h1
__global__ void 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__ drdy
__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
__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 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 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
__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 const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g11
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ ds
__global__ void const T *__restrict__ x
__global__ void const T *__restrict__ const T *__restrict__ dr
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dt
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ vz
__global__ void const T *__restrict__ const T *__restrict__ vx
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ vy
double real
#define NEKO_DMMA_CANDIDATES
@ DMMA_CUBE
@ DMMA_MAT
@ DMMA_P
static bool dmma_tma_aligned(const void *w, const void *u, const void *h1, const void *g11, const void *g22, const void *g33, const void *g12, const void *g13, const void *g23)
#define DMMA_NG
static bool dmma_tma_vector_aligned(const void *au, const void *av, const void *aw, const void *u, const void *v, const void *w, const void *h1, const void *g11, const void *g22, const void *g33, const void *g12, const void *g13, const void *g23)
static bool cuda_have_tma_conv1()
static bool dmma_tma_cdtp_aligned(const void *dtx, const void *x, const void *dr, const void *ds, const void *dt)
static bool cuda_have_tma_batch()
static bool dmma_tma_batch_lx_supported()
#define NEKO_OPGRAD_TMA_SMEM
static bool dmma_tma_vector_lx_supported()
static bool tma_arch_compiled()
#define NEKO_CONV1_TMA_SMEM
static bool dmma_tma_cdtp_lx_supported()
static int cuda_tma_smem_optin()
static bool dmma_tma_dudxyz_lx_supported()
static bool cuda_have_tma_opgrad()
static bool dmma_tma_conv1_lx_supported()
static bool dmma_tma_lx_supported()
static int neko_dmma_tma_env()
static bool dmma_tma_metrics_aligned(const void *drdx, const void *dsdx, const void *dtdx, const void *drdy, const void *dsdy, const void *dtdy, const void *drdz, const void *dsdz, const void *dtdz)
#define NEKO_DMMA_TMA_BATCH_SMEM
static bool dmma_tma_opgrad_aligned(const void *u, const void *drdx, const void *dsdx, const void *dtdx, const void *drdy, const void *dsdy, const void *dtdy, const void *drdz, const void *dsdz, const void *dtdz)
static bool dmma_tma_opgrad_lx_supported()
static bool dmma_tma_conv1_aligned(const void *du, const void *u, const void *vx, const void *vy, const void *vz, const void *jacinv, const void *drdx, const void *dsdx, const void *dtdx, const void *drdy, const void *dsdy, const void *dtdy, const void *drdz, const void *dsdz, const void *dtdz)
static bool dmma_tma_dudxyz_aligned(const void *du, const void *u, const void *dr, const void *ds, const void *dt, const void *jacinv)
static bool cuda_have_tma()
#define DMMA_NG_OPGRAD
#define DMMA_NG_CONV1
static bool dmma_tma_ptr_aligned(const void *p)
unsigned long long bar_u
double dz[DMMA_MAT]
double r[DMMA_CUBE]
double s[DMMA_CUBE]
double t[DMMA_CUBE]
unsigned long long bar_g
double g[13][DMMA_CUBE]
double u[DMMA_CUBE]
double dx[DMMA_MAT]
double dy[DMMA_MAT]
double c[3][DMMA_CUBE]
double dz[DMMA_MAT]
double t[DMMA_CUBE]
double s[DMMA_CUBE]
double g[7][DMMA_CUBE]
double r[DMMA_CUBE]
double dx[DMMA_MAT]
unsigned long long bar_a
unsigned long long bar_b
double dy[DMMA_MAT]
double dz[DMMA_MAT]
double u[DMMA_CUBE]
double s[DMMA_CUBE]
double g[9][DMMA_CUBE]
double r[DMMA_CUBE]
double t[DMMA_CUBE]
double dx[DMMA_MAT]
double dy[DMMA_MAT]
unsigned long long bar_u
unsigned long long bar_g