Neko 1.99.7
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
elem_block.h
Go to the documentation of this file.
1#ifndef __MATH_ELEM_BLOCK_H__
2#define __MATH_ELEM_BLOCK_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
56#ifndef NEKO_EB_WAVE
57#define NEKO_EB_WAVE 64
58#endif
59
60/* LDS per CU, and the per workgroup maximum, on CDNA */
61#ifndef NEKO_EB_MAX_LDS
62#define NEKO_EB_MAX_LDS 65536
63#endif
64
65#define NEKO_EB_CANDIDATES 3
66
67template< int LX, int C >
68struct elem_block {
69 static const int waves = 2 << C;
70 static const int fit = (NEKO_EB_WAVE * waves)/(LX * LX);
71 static const int value = (C == 0) ? 1 : (fit > 0 ? fit : 1);
72};
73
74/*
75 * Launch bounds.
76 *
77 * HIP's second argument is MIN_WARPS_PER_EXECUTION_UNIT -- minimum wavefronts
78 * resident per SIMD -- and not CUDA's min blocks per SM. The 3 these kernels
79 * have always carried asks for 3 waves per SIMD, i.e. a 512/3 VGPR budget,
80 * and is kept so that widening the block does not silently change the
81 * register allocation. The first argument must track the real block size:
82 * launching more threads than declared is a launch failure, not a slowdown.
83 */
84#ifndef NEKO_EB_MIN_WAVES_EU
85#define NEKO_EB_MIN_WAVES_EU 3
86#endif
87
88#define NEKO_EB_BOUNDS(NT) __launch_bounds__((NT), NEKO_EB_MIN_WAVES_EU)
89
90/*
91 * Launch geometry helpers. NELV is the element count; the grid is sized so
92 * the tail block is partially filled and clamps, rather than the kernel
93 * returning early -- these kernels have __syncthreads() in the k loop, so an
94 * early return would leave the barrier unmatched.
95 */
96#define NEKO_EB(LX, C) (elem_block<LX, C>::value)
97#define NEKO_EB_NTHRDS(LX, C) dim3((LX), (LX), NEKO_EB(LX, C))
98#define NEKO_EB_NBLCKS(NELV, LX, C) \
99 dim3(((NELV) + NEKO_EB(LX, C) - 1)/NEKO_EB(LX, C), 1, 1)
100#define NEKO_EB_SEL(LX, SEL) \
101 ((SEL) == 0 ? NEKO_EB(LX, 0) : (SEL) == 1 ? NEKO_EB(LX, 1) : NEKO_EB(LX, 2))
102
117#define NEKO_CHUNKS_CANDIDATES 4
118
119/*
120 * Candidate C selects 1024 >> C, i.e. 1024, 512, 256, 128. Candidate 0 is the
121 * historical value, so it is always available as an A/B baseline.
122 *
123 * A heuristic is deliberately avoided here. The best chunk depends on how the
124 * shared memory footprint (which grows as LX^3) caps the resident block count
125 * on the target device, and that differs between architectures -- 164 kB per
126 * SM on A100, 228 kB on H100, 64 kB of LDS per CU on CDNA. Picking by thread
127 * utilisation alone gets it wrong from LX = 6 upward, because once the block
128 * count is capped by shared memory a smaller block simply wastes thread slots.
129 * So all four are instantiated and the tuner measures them.
130 */
131template< int LX, int C >
132struct chunk_block {
133 static const int raw = 1024 >> C;
134 static const int value = (raw >= LX * LX) ? raw : 1024;
135};
136
137#define NEKO_CHUNKS(LX, C) (chunk_block<LX, C>::value)
138#define NEKO_CHUNKS_NTHRDS(LX, C) dim3(NEKO_CHUNKS(LX, C), 1, 1)
139#define NEKO_CHUNKS_SEL(LX, SEL) \
140 ((SEL) == 0 ? NEKO_CHUNKS(LX, 0) : (SEL) == 1 ? NEKO_CHUNKS(LX, 1) : \
141 (SEL) == 2 ? NEKO_CHUNKS(LX, 2) : NEKO_CHUNKS(LX, 3))
142
143#endif // __MATH_ELEM_BLOCK_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)
#define NEKO_EB_WAVE
Definition elem_block.h:57
static const int raw
Definition elem_block.h:141
static const int value
Definition elem_block.h:142
static const int waves
Definition elem_block.h:69
static const int fit
Definition elem_block.h:70
static const int value
Definition elem_block.h:68