Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
ax_helm.hip
Go to the documentation of this file.
1/*
2 Copyright (c) 2021-2026, The Neko Authors
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16
17 * Neither the name of the authors nor the names of its
18 contributors may be used to endorse or promote products derived
19 from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33*/
34
35#include <string.h>
36#include <stdlib.h>
37#include <stdio.h>
38#include <hip/hip_runtime.h>
40#include <device/hip/check.h>
41#include "ax_helm_kernel.h"
42#include "elem_block_tune.h"
43
44extern "C" {
45 #include <common/neko_log.h>
46}
47
48template < const int>
49int tune(void *w, void *u, void *dx, void *dy, void *dz,
50 void *dxt, void *dyt, void *dzt, void *h1,
51 void *g11, void *g22, void *g33, void *g12,
52 void *g13, void *g23, int *nelv, int *lx, int *eb_sel, int *ch_sel,
53 int *nwf_sel);
54
55template < const int>
56int tune_padded(void *w, void *u, void *dx, void *dy, void *dz,
57 void *dxt, void *dyt, void *dzt, void *h1,
58 void *g11, void *g22, void *g33, void *g12,
59 void *g13, void *g23, int *nelv, int *lx, int *eb_sel,
60 int *ch_sel, int *nwf_sel);
61
62template < const int>
63int tune_vector(void *au, void *av, void *aw, void *u, void *v, void *w,
64 void *dx, void *dy, void *dz, void *h1,
65 void *g11, void *g22, void *g33, void *g12,
66 void *g13, void *g23, int *nelv, int *lx, int *eb_sel,
67 int *nwf_sel);
68
69template < const int>
70int tune_vector_padded(void *au, void *av, void *aw,
71 void *u, void *v, void *w,
72 void *dx, void *dy, void *dz, void *h1,
73 void *g11, void *g22, void *g33, void *g12,
74 void *g13, void *g23, int *nelv, int *lx, int *eb_sel,
75 int *nwf_sel);
76
77extern "C" {
78
82 void hip_ax_helm(void *w, void *u, void *dx, void *dy, void *dz,
83 void *dxt, void *dyt, void *dzt, void *h1,
84 void *g11, void *g22, void *g33, void *g12,
85 void *g13, void *g23, int *nelv, int *lx) {
86
87 static int autotune[13] = { 0 };
88 /* Elements per block candidate chosen by the autotuner, see
89 elem_block<> in elem_block.h */
90 static int autotune_eb[13] = { 0 };
91 /* chunk candidate chosen for the 1d variant */
92 static int autotune_ch[13] = { 0 };
93 /* wavefronts per block candidate chosen for the mfma variant */
94 static int autotune_nwf[13] = { 0 };
95
96 const dim3 nthrds_1d(1024, 1, 1);
97 const dim3 nblcks_1d((*nelv), 1, 1);
98
99#define CASE_1D(LX, C) \
100 hipLaunchKernelGGL(HIP_KERNEL_NAME( \
101 ax_helm_kernel_1d<real, LX, NEKO_CHUNKS(LX, C)> ), \
102 nblcks_1d, NEKO_CHUNKS_NTHRDS(LX, C), 0, \
103 (hipStream_t) glb_cmd_queue, \
104 (real *) w, (real *) u, \
105 (real *) dx, (real *) dy, (real *) dz, \
106 (real *) dxt, (real *) dyt, (real *) dzt, (real *) h1, \
107 (real *) g11, (real *) g22, (real *) g33, \
108 (real *) g12, (real *) g13, (real *) g23); \
109 HIP_CHECK(hipGetLastError());
110
111/* Runtime dispatch onto the tuned chunk candidate */
112#define CASE_1D_SEL(LX, SEL) \
113 switch (SEL) { \
114 case 0: CASE_1D(LX, 0); break; \
115 case 1: CASE_1D(LX, 1); break; \
116 case 2: CASE_1D(LX, 2); break; \
117 default: CASE_1D(LX, 3); break; \
118 }
119
120#define CASE_KSTEP(LX, C) \
121 hipLaunchKernelGGL( HIP_KERNEL_NAME( \
122 ax_helm_kernel_kstep<real, LX, NEKO_EB(LX, C)> ), \
123 NEKO_EB_NBLCKS(*nelv, LX, C), NEKO_EB_NTHRDS(LX, C), 0, \
124 (hipStream_t) glb_cmd_queue, \
125 (real *) w, (real *) u, \
126 (real *) dx, (real *) dy, (real *) dz, (real *) h1, \
127 (real *) g11, (real *) g22, (real *) g33, \
128 (real *) g12, (real *) g13, (real *) g23, *nelv); \
129 HIP_CHECK(hipGetLastError());
130
131#define CASE_KSTEP_PADDED(LX, C) \
132 hipLaunchKernelGGL( HIP_KERNEL_NAME( \
133 ax_helm_kernel_kstep_padded<real, LX, NEKO_EB(LX, C)> ),\
134 NEKO_EB_NBLCKS(*nelv, LX, C), NEKO_EB_NTHRDS(LX, C), 0, \
135 (hipStream_t) glb_cmd_queue, \
136 (real *) w, (real *) u, \
137 (real *) dx, (real *) dy, (real *) dz, (real *) h1, \
138 (real *) g11, (real *) g22, (real *) g33, \
139 (real *) g12, (real *) g13, (real *) g23, *nelv); \
140 HIP_CHECK(hipGetLastError());
141
142#define CASE_MFMA(LX, C) \
143 hipLaunchKernelGGL( HIP_KERNEL_NAME( \
144 ax_helm_kernel_mfma<real, LX, NEKO_MFMA_NWF(C), \
145 NEKO_MFMA_TILE(C)> ), \
146 NEKO_MFMA_NBLCKS(*nelv, LX, C), NEKO_MFMA_NTHRDS(C), 0, \
147 (hipStream_t) glb_cmd_queue, \
148 (real *) w, (real *) u, \
149 (real *) dx, (real *) dy, (real *) dz, (real *) h1, \
150 (real *) g11, (real *) g22, (real *) g33, \
151 (real *) g12, (real *) g13, (real *) g23, *nelv); \
152 HIP_CHECK(hipGetLastError());
153
154/* Runtime dispatch onto the tuned candidate, which names both the wavefronts
155 per block and the matrix core tile, see NEKO_MFMA_TILE in mfma_kernel.h */
156#define CASE_MFMA_SEL(LX, SEL) \
157 switch (SEL) { \
158 case 0: CASE_MFMA(LX, 0); break; \
159 case 1: CASE_MFMA(LX, 1); break; \
160 case 2: CASE_MFMA(LX, 2); break; \
161 case 3: CASE_MFMA(LX, 3); break; \
162 case 4: CASE_MFMA(LX, 4); break; \
163 case 5: CASE_MFMA(LX, 5); break; \
164 case 6: CASE_MFMA(LX, 6); break; \
165 case 7: CASE_MFMA(LX, 7); break; \
166 case 8: CASE_MFMA(LX, 8); break; \
167 default: CASE_MFMA(LX, 9); break; \
168 }
169
170/* The switch above has to name every candidate. A candidate that fell
171 through to the default arm would launch its own grid and block shape --
172 NEKO_MFMA_NBLCKS and NEKO_MFMA_NTHRDS are evaluated at the call site --
173 at a kernel compiled for a different wavefront count, which is a launch
174 failure where the block is bigger and silent corruption where it is not.
175 Raising the candidate count without extending the switch stops here. */
176static_assert(NEKO_MFMA_CANDIDATES == 10,
177 "CASE_MFMA_SEL does not cover the candidate space");
178
179/* Runtime dispatch onto the tuned elements per block candidate */
180#define CASE_KSTEP_SEL(LX, SEL) \
181 switch (SEL) { \
182 case 0: CASE_KSTEP(LX, 0); break; \
183 case 1: CASE_KSTEP(LX, 1); break; \
184 default: CASE_KSTEP(LX, 2); break; \
185 }
186
187#define CASE_KSTEP_PADDED_SEL(LX, SEL) \
188 switch (SEL) { \
189 case 0: CASE_KSTEP_PADDED(LX, 0); break; \
190 case 1: CASE_KSTEP_PADDED(LX, 1); break; \
191 default: CASE_KSTEP_PADDED(LX, 2); break; \
192 }
193
194#define CASE(LX) \
195 case LX: \
196 if(autotune[LX] == 0 ) { \
197 autotune[LX]=tune<LX>( w, u, \
198 dx, dy, dz, \
199 dxt, dyt, dzt,h1, \
200 g11, g22, g33, \
201 g12, g13, g23, nelv, lx, \
202 &autotune_eb[LX], &autotune_ch[LX], \
203 &autotune_nwf[LX]); \
204 } else if (autotune[LX] == 1 ) { \
205 CASE_1D_SEL(LX, autotune_ch[LX]); \
206 } else if (autotune[LX] == 2 ) { \
207 CASE_KSTEP_SEL(LX, autotune_eb[LX]); \
208 } else if (autotune[LX] == 3 ) { \
209 CASE_MFMA_SEL(LX, autotune_nwf[LX]); \
210 } \
211 break
212
213#define CASE_PADDED(LX) \
214 case LX: \
215 if(autotune[LX] == 0 ) { \
216 autotune[LX]=tune_padded<LX>(w, u, \
217 dx, dy, dz, \
218 dxt, dyt, dzt,h1, \
219 g11, g22, g33, \
220 g12, g13, g23,nelv,lx, \
221 &autotune_eb[LX], &autotune_ch[LX], \
222 &autotune_nwf[LX]); \
223 } else if (autotune[LX] == 1 ) { \
224 CASE_1D_SEL(LX, autotune_ch[LX]); \
225 } else if (autotune[LX] == 2 ) { \
226 CASE_KSTEP_PADDED_SEL(LX, autotune_eb[LX]); \
227 } else if (autotune[LX] == 3 ) { \
228 CASE_MFMA_SEL(LX, autotune_nwf[LX]); \
229 } \
230 break
231
232/*
233 * High order cases have no 1d variant to compare against (its LDS footprint
234 * grows as LX^3), so they are not tuned and keep one element per block,
235 * i.e. candidate 0
236 */
237#define CASE_LARGE(LX) \
238 case LX: \
239 CASE_KSTEP(LX, 0); \
240 break
241
242#define CASE_LARGE_PADDED(LX) \
243 case LX: \
244 CASE_KSTEP_PADDED(LX, 0); \
245 break
246
247 if ((*lx) < 13) {
248 switch(*lx) {
249 CASE(2);
250 CASE(3);
251 CASE(4);
252 CASE(5);
253 CASE(6);
254 CASE(7);
255 CASE_PADDED(8);
256 CASE(9);
257 CASE(10);
258 CASE(11);
259 CASE(12);
260 default:
261 {
262 fprintf(stderr, __FILE__ ": size not supported: %d\n", *lx);
263 exit(1);
264 }
265 }
266 }
267 else {
268 switch(*lx) {
269 CASE_LARGE(13);
270 CASE_LARGE(14);
271 CASE_LARGE(15);
273 default:
274 {
275 fprintf(stderr, __FILE__ ": size not supported: %d\n", *lx);
276 exit(1);
277 }
278 }
279 }
280 }
284 void hip_ax_helm_vector(void *au, void *av, void *aw,
285 void *u, void *v, void *w,
286 void *dx, void *dy, void *dz,
287 void *dxt, void *dyt, void *dzt,
288 void *h1, void *g11, void *g22,
289 void *g33, void *g12, void *g13,
290 void *g23, int *nelv, int *lx) {
291
292 /* Strategy chosen by the autotuner: 0 untuned, 2 kstep, 3 mfma. There
293 is no 1d variant of the vector operator, so the kstep family is the
294 baseline and the matrix core variant the only alternative */
295 static int autotune_v[17] = { 0 };
296 /* elements per block candidate chosen for the kstep variant */
297 static int autotune_v_eb[17] = { 0 };
298 /* wavefronts per block candidate chosen for the mfma variant */
299 static int autotune_v_nwf[17] = { 0 };
300
301#define CASE_VECTOR_KSTEP(LX, C) \
302 hipLaunchKernelGGL( HIP_KERNEL_NAME( \
303 ax_helm_kernel_vector_kstep<real, LX, \
304 NEKO_EB(LX, C)> ), \
305 NEKO_EB_NBLCKS(*nelv, LX, C), NEKO_EB_NTHRDS(LX, C), 0, \
306 (hipStream_t) glb_cmd_queue, \
307 (real *) au, (real *) av, (real *) aw, \
308 (real *) u, (real *) v, (real *) w, \
309 (real *) dx, (real *) dy, (real *) dz, (real *) h1, \
310 (real *) g11, (real *) g22, (real *) g33, \
311 (real *) g12, (real *) g13, (real *) g23, *nelv); \
312 HIP_CHECK(hipGetLastError());
313
314#define CASE_VECTOR_KSTEP_PADDED(LX, C) \
315 hipLaunchKernelGGL( HIP_KERNEL_NAME( \
316 ax_helm_kernel_vector_kstep_padded<real, LX, \
317 NEKO_EB(LX, C)> ), \
318 NEKO_EB_NBLCKS(*nelv, LX, C), NEKO_EB_NTHRDS(LX, C), 0, \
319 (hipStream_t) glb_cmd_queue, \
320 (real *) au, (real *) av, (real *) aw, \
321 (real *) u, (real *) v, (real *) w, \
322 (real *) dx, (real *) dy, (real *) dz, (real *) h1, \
323 (real *) g11, (real *) g22, (real *) g33, \
324 (real *) g12, (real *) g13, (real *) g23, *nelv); \
325 HIP_CHECK(hipGetLastError());
326
327/* The matrix core variant: same grid and wavefronts per block candidates as
328 the scalar CASE_MFMA, see mfma_kernel.h */
329#define CASE_VECTOR_MFMA(LX, C) \
330 hipLaunchKernelGGL( HIP_KERNEL_NAME( \
331 ax_helm_kernel_mfma_vector<real, LX, \
332 NEKO_MFMA_NWF(C), \
333 NEKO_MFMA_TILE(C)> ), \
334 NEKO_MFMA_NBLCKS(*nelv, LX, C), NEKO_MFMA_NTHRDS(C), 0, \
335 (hipStream_t) glb_cmd_queue, \
336 (real *) au, (real *) av, (real *) aw, \
337 (real *) u, (real *) v, (real *) w, \
338 (real *) dx, (real *) dy, (real *) dz, (real *) h1, \
339 (real *) g11, (real *) g22, (real *) g33, \
340 (real *) g12, (real *) g13, (real *) g23, *nelv); \
341 HIP_CHECK(hipGetLastError());
342
343#define CASE_VECTOR_KSTEP_SEL(LX, SEL) \
344 switch (SEL) { \
345 case 0: CASE_VECTOR_KSTEP(LX, 0); break; \
346 case 1: CASE_VECTOR_KSTEP(LX, 1); break; \
347 default: CASE_VECTOR_KSTEP(LX, 2); break; \
348 }
349
350#define CASE_VECTOR_KSTEP_PADDED_SEL(LX, SEL) \
351 switch (SEL) { \
352 case 0: CASE_VECTOR_KSTEP_PADDED(LX, 0); break; \
353 case 1: CASE_VECTOR_KSTEP_PADDED(LX, 1); break; \
354 default: CASE_VECTOR_KSTEP_PADDED(LX, 2); break; \
355 }
356
357/* Runtime dispatch onto the tuned candidate, see CASE_MFMA_SEL */
358#define CASE_VECTOR_MFMA_SEL(LX, SEL) \
359 switch (SEL) { \
360 case 0: CASE_VECTOR_MFMA(LX, 0); break; \
361 case 1: CASE_VECTOR_MFMA(LX, 1); break; \
362 case 2: CASE_VECTOR_MFMA(LX, 2); break; \
363 case 3: CASE_VECTOR_MFMA(LX, 3); break; \
364 case 4: CASE_VECTOR_MFMA(LX, 4); break; \
365 case 5: CASE_VECTOR_MFMA(LX, 5); break; \
366 case 6: CASE_VECTOR_MFMA(LX, 6); break; \
367 case 7: CASE_VECTOR_MFMA(LX, 7); break; \
368 case 8: CASE_VECTOR_MFMA(LX, 8); break; \
369 default: CASE_VECTOR_MFMA(LX, 9); break; \
370 }
371
372/* The switch above has to name every candidate. A candidate that fell
373 through to the default arm would launch its own grid and block shape --
374 NEKO_MFMA_NBLCKS and NEKO_MFMA_NTHRDS are evaluated at the call site --
375 at a kernel compiled for a different wavefront count, which is a launch
376 failure where the block is bigger and silent corruption where it is not.
377 Raising the candidate count without extending the switch stops here. */
378static_assert(NEKO_MFMA_CANDIDATES == 10,
379 "CASE_VECTOR_MFMA_SEL does not cover the candidate space");
380
381#define CASE_VECTOR(LX) \
382 case LX: \
383 if (autotune_v[LX] == 0) { \
384 autotune_v[LX] = tune_vector<LX>(au, av, aw, u, v, w, \
385 dx, dy, dz, h1, \
386 g11, g22, g33, \
387 g12, g13, g23, nelv, lx, \
388 &autotune_v_eb[LX], \
389 &autotune_v_nwf[LX]); \
390 } else if (autotune_v[LX] == 2) { \
391 CASE_VECTOR_KSTEP_SEL(LX, autotune_v_eb[LX]); \
392 } else if (autotune_v[LX] == 3) { \
393 CASE_VECTOR_MFMA_SEL(LX, autotune_v_nwf[LX]); \
394 } \
395 break
396
397#define CASE_VECTOR_PADDED(LX) \
398 case LX: \
399 if (autotune_v[LX] == 0) { \
400 autotune_v[LX] = tune_vector_padded<LX>(au, av, aw, u, v, w, \
401 dx, dy, dz, h1, \
402 g11, g22, g33, \
403 g12, g13, g23, nelv, lx, \
404 &autotune_v_eb[LX], \
405 &autotune_v_nwf[LX]); \
406 } else if (autotune_v[LX] == 2) { \
407 CASE_VECTOR_KSTEP_PADDED_SEL(LX, autotune_v_eb[LX]); \
408 } else if (autotune_v[LX] == 3) { \
409 CASE_VECTOR_MFMA_SEL(LX, autotune_v_nwf[LX]); \
410 } \
411 break
412
413 switch(*lx) {
414 CASE_VECTOR(2);
415 CASE_VECTOR(3);
417 CASE_VECTOR(5);
418 CASE_VECTOR(6);
419 CASE_VECTOR(7);
421 CASE_VECTOR(9);
422 CASE_VECTOR(10);
423 CASE_VECTOR(11);
424 CASE_VECTOR(12);
425 CASE_VECTOR(13);
426 CASE_VECTOR(14);
427 CASE_VECTOR(15);
429 default:
430 {
431 fprintf(stderr, __FILE__ ": size not supported: %d\n", *lx);
432 exit(1);
433 }
434 }
435 }
436
440 void hip_ax_helm_vector_part2(void *au, void *av, void *aw,
441 void *u, void *v, void *w,
442 void *h2, void *B, int *n) {
443
444 const dim3 nthrds(1024, 1, 1);
445 const dim3 nblcks(((*n)+1024 - 1)/ 1024, 1, 1);
446 const hipStream_t stream = (hipStream_t) glb_cmd_queue;
447
449 nblcks, nthrds, 0, stream,
450 (real *) au, (real *) av, (real *) aw,
451 (real *) u, (real *) v, (real *) w,
452 (real *) h2, (real *) B, *n);
453 }
454
455}
456
457template < const int LX >
458int tune(void *w, void *u, void *dx, void *dy, void *dz,
459 void *dxt, void *dyt, void *dzt, void *h1,
460 void *g11, void *g22, void *g33, void *g12,
461 void *g13, void *g23, int *nelv, int *lx, int *eb_sel, int *ch_sel,
462 int *nwf_sel) {
465 int best1 = 0;
468 int best3 = 0;
469 const int rounds = neko_tune_rounds();
470 const int iters = neko_tune_iters();
471 /* Candidates of the kstep sweep, one -- the unblocked shape -- when the
472 elements per block sweep is off */
473 const int eb_cand = neko_eb_sweep() ? NEKO_EB_CANDIDATES : 1;
474 /* Candidates of the matrix core sweep, see neko_mfma_candidates() */
475 const int mfma_cand = neko_mfma_candidates();
476 /* Geometry pinned by each formulation's own variable, -1 to sweep it */
477 const int ch_pin = neko_chunks_pin();
478 const int eb_pin = neko_eb_pin();
479 const int nwf_pin = neko_mfma_pin();
480 /* Formulation pinned by NEKO_AUTOTUNE, as the identifier tune() returns */
481 int strat = 0;
482 /* Hardware capability, which the explicit NEKO_AUTOTUNE=MFMA pin needs */
483 const bool mfma = mfma_lx_supported<LX>() && hip_have_mfma();
484 int best = 0;
485 int retval;
486
487 for (int c = 0; c < NEKO_EB_CANDIDATES; c++) {
489 }
490 for (int c = 0; c < NEKO_CHUNKS_CANDIDATES; c++) {
492 }
493 for (int c = 0; c < NEKO_MFMA_CANDIDATES; c++) {
495 }
496
497 const dim3 nthrds_1d(1024, 1, 1);
498 const dim3 nblcks_1d((*nelv), 1, 1);
499 const hipStream_t stream = (hipStream_t) glb_cmd_queue;
500
501 char *env_value = NULL;
502 char neko_log_buf[80];
503
504 env_value=getenv("NEKO_AUTOTUNE");
505
506 sprintf(neko_log_buf, "Autotune Ax helm (lx: %d)", *lx);
508
509 *eb_sel = 0;
510 *ch_sel = 0;
511 *nwf_sel = 0;
512
513 /*
514 * NEKO_AUTOTUNE names a formulation, and that is all it does: the sweep
515 * below is narrowed to that one kernel family, but its geometry -- the
516 * chunk size, the elements per block, the wavefronts per block -- is still
517 * measured candidate against candidate. A formulation this build or this
518 * device does not have is reported and ignored, leaving the full sweep.
519 */
520 if(env_value) {
521 if( !strcmp(env_value,"1D") ) {
522 strat = 1;
523 } else if( !strcmp(env_value,"KSTEP") ) {
524 strat = 2;
525 } else if( !strcmp(env_value,"MFMA") ) {
526 if (mfma) {
527 strat = 3;
528 } else {
529 sprintf(neko_log_buf, "MFMA strategy not available for this config");
531 }
532 } else {
533 sprintf(neko_log_buf, "Invalid value set for NEKO_AUTOTUNE");
535 }
536 }
537
538 /* Geometry of the pinned formulation, if its own variable fixes that too.
539 Both pinned leaves nothing to measure, so the kernel is launched once and
540 reported, which is what pinning has always done */
541 const int pin = (strat == 1) ? ch_pin : (strat == 2) ? eb_pin :
542 (strat == 3) ? nwf_pin : -1;
543
544 if (pin >= 0) {
545 switch (strat) {
546 case 1:
547 *ch_sel = pin;
549 sprintf(neko_log_buf, "Set by env : 1 (1D, %d chunk)",
551 break;
552 case 2:
553 *eb_sel = pin;
555 sprintf(neko_log_buf, "Set by env : 2 (KSTEP, %d elem/block)",
556 NEKO_EB_SEL(LX, pin));
557 break;
558 default:
559 *nwf_sel = pin;
561 sprintf(neko_log_buf, "Set by env : 3 (MFMA %s, %d wf, %d elem/blk)",
563 break;
564 }
567 return strat;
568 }
569
570 if (strat) {
571 sprintf(neko_log_buf, "Set by env : %d (%s)", strat, env_value);
573 }
574
575 /* Formulations the sweep considers, see NEKO_TUNE_FOR(). NEKO_MFMA_TUNE
576 keeps the matrix core variant out of an unpinned sweep, but naming it
577 explicitly still measures it */
578 const bool try_1d = (strat == 0 || strat == 1);
579 const bool try_kstep = (strat == 0 || strat == 2);
580 const bool try_mfma = mfma && ((strat == 3) ||
581 (strat == 0 && neko_mfma_sweep()));
582
585
586 /* Verify every candidate against the reference formulation on a synthetic
587 input before anything is timed, see neko_tune_verify_begin() in
588 elem_block_tune.h. A candidate that does not reproduce it is reported
589 and dropped from the comparison below. */
590 neko_tune_rej_t rej1 = {{0}}, rej2 = {{0}}, rej3 = {{0}};
591 {
593 real *vouts[] = { (real *) w };
594 void **vins[] = { &u };
595 if (neko_tune_verify_begin(&vf, vouts, 1, vins, 1,
596 (*nelv) * LX * LX * LX, stream)) {
597 sprintf(neko_log_buf, "Verify : rel tol %.1e, synthetic input",
598 vf.tol);
600 CASE_1D_SEL(LX, 0);
601 neko_tune_verify_ref(&vf, stream);
604 }
607 }
610 }
611 neko_tune_verify_end(&vf, stream);
612 } else {
613 sprintf(neko_log_buf, "Verify : %s", neko_tune_verify_on() ?
614 "skipped, no memory for it" : "off (NEKO_TUNE_VERIFY=0)");
616 }
617 }
618
619 /* Warm every variant before timing anything: each specialisation has to
620 be resident and the clocks at steady state, or whichever variant is
621 timed first is measured on a colder part */
622 for (int i = 0; i < NEKO_TUNE_WARMUP; i++) {
624 CASE_1D_SEL(LX, c);
625 }
627 CASE_KSTEP_SEL(LX, c);
628 }
630 CASE_MFMA_SEL(LX, c);
631 }
632 }
633
634 /* Interleaved rounds, best time per variant: timing them one after another
635 in a fixed order lets clock drift bias the comparison by position */
636 for (int r = 0; r < rounds; r++) {
639 }
642 }
645 }
646 }
647
648 /* Candidates the verification pass rejected drop out here, after the
649 timing, so the sweep's own bookkeeping is untouched */
653
656
660 *eb_sel = best;
661 *ch_sel = best1;
662 *nwf_sel = best3;
663
664 if (time1[best1] < time2[best]) {
665 retval = 1;
666 } else {
667 retval = 2;
668 }
669
670 /* The mfma variant joins the comparison only where it exists, its
671 candidates are left at NEKO_TUNE_INIT otherwise */
672 if (time3[best3] < ((retval == 1) ? time1[best1] : time2[best])) {
673 retval = 3;
674 }
675
678
679 /* The tuner stands in for a real Ax evaluation, and the variants do not
680 sum in the same order, so leave the output of the chosen kernel in w */
681 if (retval == 1) {
683 } else if (retval == 2) {
685 } else {
687 }
688
689 if (retval == 1) {
690 sprintf(neko_log_buf, "Chose : 1 (1D, %d chunk)",
692 } else if (retval == 2) {
693 sprintf(neko_log_buf, "Chose : 2 (KSTEP, %d elem/block)",
695 } else {
696 sprintf(neko_log_buf, "Chose : 3 (MFMA %s, %d wf, %d elem/blk)",
699 }
702 return retval;
703}
704
705template < const int LX >
706int tune_padded(void *w, void *u, void *dx, void *dy, void *dz,
707 void *dxt, void *dyt, void *dzt, void *h1,
708 void *g11, void *g22, void *g33, void *g12,
709 void *g13, void *g23, int *nelv, int *lx,
710 int *eb_sel, int *ch_sel, int *nwf_sel) {
713 int best1 = 0;
716 int best3 = 0;
717 const int rounds = neko_tune_rounds();
718 const int iters = neko_tune_iters();
719 /* Candidates of the kstep sweep, see tune() */
720 const int eb_cand = neko_eb_sweep() ? NEKO_EB_CANDIDATES : 1;
721 /* Candidates of the matrix core sweep, see neko_mfma_candidates() */
722 const int mfma_cand = neko_mfma_candidates();
723 /* Geometry pinned by each formulation's own variable, -1 to sweep it */
724 const int ch_pin = neko_chunks_pin();
725 const int eb_pin = neko_eb_pin();
726 const int nwf_pin = neko_mfma_pin();
727 /* Formulation pinned by NEKO_AUTOTUNE, as the identifier this returns */
728 int strat = 0;
729 /* Hardware capability, which the explicit NEKO_AUTOTUNE=MFMA pin needs */
730 const bool mfma = mfma_lx_supported<LX>() && hip_have_mfma();
731 int best = 0;
732 int retval;
733
734 for (int c = 0; c < NEKO_EB_CANDIDATES; c++) {
736 }
737 for (int c = 0; c < NEKO_CHUNKS_CANDIDATES; c++) {
739 }
740 for (int c = 0; c < NEKO_MFMA_CANDIDATES; c++) {
742 }
743
744 const dim3 nthrds_1d(1024, 1, 1);
745 const dim3 nblcks_1d((*nelv), 1, 1);
746 const hipStream_t stream = (hipStream_t) glb_cmd_queue;
747
748 char *env_value = NULL;
749 char neko_log_buf[80];
750
751 env_value=getenv("NEKO_AUTOTUNE");
752
753 sprintf(neko_log_buf, "Autotune Ax helm (lx: %d)", *lx);
755
756 *eb_sel = 0;
757 *ch_sel = 0;
758 *nwf_sel = 0;
759
760 /* NEKO_AUTOTUNE names a formulation and nothing more, see tune() */
761 if(env_value) {
762 if( !strcmp(env_value,"1D") ) {
763 strat = 1;
764 } else if( !strcmp(env_value,"KSTEP") ) {
765 strat = 2;
766 } else if( !strcmp(env_value,"MFMA") ) {
767 if (mfma) {
768 strat = 3;
769 } else {
770 sprintf(neko_log_buf, "MFMA strategy not available for this config");
772 }
773 } else {
774 sprintf(neko_log_buf, "Invalid value set for NEKO_AUTOTUNE");
776 }
777 }
778
779 /* Formulation and geometry both pinned leaves nothing to measure */
780 const int pin = (strat == 1) ? ch_pin : (strat == 2) ? eb_pin :
781 (strat == 3) ? nwf_pin : -1;
782
783 if (pin >= 0) {
784 switch (strat) {
785 case 1:
786 *ch_sel = pin;
788 sprintf(neko_log_buf, "Set by env : 1 (1D, %d chunk)",
790 break;
791 case 2:
792 *eb_sel = pin;
794 sprintf(neko_log_buf, "Set by env : 2 (KSTEP, %d elem/block)",
795 NEKO_EB_SEL(LX, pin));
796 break;
797 default:
798 *nwf_sel = pin;
800 sprintf(neko_log_buf, "Set by env : 3 (MFMA %s, %d wf, %d elem/blk)",
802 break;
803 }
806 return strat;
807 }
808
809 if (strat) {
810 sprintf(neko_log_buf, "Set by env : %d (%s)", strat, env_value);
812 }
813
814 /* Formulations the sweep considers, see NEKO_TUNE_FOR() */
815 const bool try_1d = (strat == 0 || strat == 1);
816 const bool try_kstep = (strat == 0 || strat == 2);
817 const bool try_mfma = mfma && ((strat == 3) ||
818 (strat == 0 && neko_mfma_sweep()));
819
822
823 /* Verify every candidate against the reference formulation on a synthetic
824 input before anything is timed, see neko_tune_verify_begin() in
825 elem_block_tune.h. A candidate that does not reproduce it is reported
826 and dropped from the comparison below. */
827 neko_tune_rej_t rej1 = {{0}}, rej2 = {{0}}, rej3 = {{0}};
828 {
830 real *vouts[] = { (real *) w };
831 void **vins[] = { &u };
832 if (neko_tune_verify_begin(&vf, vouts, 1, vins, 1,
833 (*nelv) * LX * LX * LX, stream)) {
834 sprintf(neko_log_buf, "Verify : rel tol %.1e, synthetic input",
835 vf.tol);
837 CASE_1D_SEL(LX, 0);
838 neko_tune_verify_ref(&vf, stream);
841 }
844 }
847 }
848 neko_tune_verify_end(&vf, stream);
849 } else {
850 sprintf(neko_log_buf, "Verify : %s", neko_tune_verify_on() ?
851 "skipped, no memory for it" : "off (NEKO_TUNE_VERIFY=0)");
853 }
854 }
855
856 /* Warm every variant before timing anything: each specialisation has to
857 be resident and the clocks at steady state, or whichever variant is
858 timed first is measured on a colder part */
859 for (int i = 0; i < NEKO_TUNE_WARMUP; i++) {
861 CASE_1D_SEL(LX, c);
862 }
865 }
867 CASE_MFMA_SEL(LX, c);
868 }
869 }
870
871 /* Interleaved rounds, best time per variant: timing them one after another
872 in a fixed order lets clock drift bias the comparison by position */
873 for (int r = 0; r < rounds; r++) {
876 }
879 }
882 }
883 }
884
885 /* Candidates the verification pass rejected drop out here, after the
886 timing, so the sweep's own bookkeeping is untouched */
890
893
897 *eb_sel = best;
898 *ch_sel = best1;
899 *nwf_sel = best3;
900
901 if (time1[best1] < time2[best]) {
902 retval = 1;
903 } else {
904 retval = 2;
905 }
906
907 /* The mfma variant joins the comparison only where it exists, its
908 candidates are left at NEKO_TUNE_INIT otherwise */
909 if (time3[best3] < ((retval == 1) ? time1[best1] : time2[best])) {
910 retval = 3;
911 }
912
915
916 /* Leave the output of the chosen kernel in w, see tune() */
917 if (retval == 1) {
919 } else if (retval == 2) {
921 } else {
923 }
924
925 if (retval == 1) {
926 sprintf(neko_log_buf, "Chose : 1 (1D, %d chunk)",
928 } else if (retval == 2) {
929 sprintf(neko_log_buf, "Chose : 2 (KSTEP, %d elem/block)",
931 } else {
932 sprintf(neko_log_buf, "Chose : 3 (MFMA %s, %d wf, %d elem/blk)",
935 }
938 return retval;
939}
940
941/*
942 * The vector Ax has no 1d variant, so the tuner picks between the kstep
943 * family -- one element per block, plus the blocked candidates when the
944 * elements per block sweep is on -- and the matrix core variant, where the
945 * device and the polynomial order allow it. NEKO_AUTOTUNE=KSTEP (or 1D,
946 * there being nothing else to pin it to) narrows the sweep to the kstep
947 * variant, NEKO_AUTOTUNE=MFMA to the matrix core one, and in both cases the
948 * geometry candidates of the named variant are still measured -- it takes
949 * NEKO_EB or NEKO_MFMA_NWF to fix that too, as for the scalar operator.
950 *
951 * @note The section title has to fit the 30 character header field in
952 * log_section(), which truncates rather than wraps -- hence "Ax vector"
953 * rather than the "Ax helm vector" it reads as. It matches the CUDA copy.
954 */
955template < const int LX >
956int tune_vector(void *au, void *av, void *aw, void *u, void *v, void *w,
957 void *dx, void *dy, void *dz, void *h1,
958 void *g11, void *g22, void *g33, void *g12,
959 void *g13, void *g23, int *nelv, int *lx, int *eb_sel,
960 int *nwf_sel) {
963 int best2 = 0;
965 int best3 = 0;
966 const int rounds = neko_tune_rounds();
967 const int iters = neko_tune_iters();
968 const int sweep = neko_eb_sweep();
969 /* Candidates of the kstep sweep, one -- the unblocked shape -- when the
970 elements per block sweep is off */
971 const int eb_cand = sweep ? NEKO_EB_CANDIDATES : 1;
972 /* Candidates of the matrix core sweep, see neko_mfma_candidates() */
973 const int mfma_cand = neko_mfma_candidates();
974 /* Geometry pinned by each formulation's own variable, -1 to sweep it */
975 const int eb_pin = neko_eb_pin();
976 const int nwf_pin = neko_mfma_pin();
977 /* Formulation pinned by NEKO_AUTOTUNE, as the identifier this returns */
978 int strat = 0;
979 /* Hardware capability, which the explicit NEKO_AUTOTUNE=MFMA pin needs */
980 const bool mfma = mfma_lx_supported<LX>() && hip_have_mfma();
981 int retval;
982
983 for (int c = 0; c < NEKO_EB_CANDIDATES; c++) {
985 }
986 for (int c = 0; c < NEKO_MFMA_CANDIDATES; c++) {
988 }
989
990 const hipStream_t stream = (hipStream_t) glb_cmd_queue;
991
992 char *env_value = NULL;
993 char neko_log_buf[80];
994
995 env_value = getenv("NEKO_AUTOTUNE");
996
997 sprintf(neko_log_buf, "Autotune Ax vector (lx: %d)", *lx);
999
1000 *eb_sel = 0;
1001 *nwf_sel = 0;
1002
1003 /* NEKO_AUTOTUNE names a formulation and nothing more, see tune() */
1004 if (env_value) {
1005 if ( !strcmp(env_value, "KSTEP") || !strcmp(env_value, "1D") ) {
1006 /* No 1d variant here, so either pin lands on kstep */
1007 strat = 2;
1008 } else if ( !strcmp(env_value, "MFMA") ) {
1009 if (mfma) {
1010 strat = 3;
1011 } else {
1012 sprintf(neko_log_buf, "MFMA strategy not available for this config");
1014 }
1015 } else {
1016 sprintf(neko_log_buf, "Invalid value set for NEKO_AUTOTUNE");
1018 }
1019 }
1020
1021 /* Formulation and geometry both pinned leaves nothing to measure */
1022 const int pin = (strat == 2) ? eb_pin : (strat == 3) ? nwf_pin : -1;
1023
1024 if (pin >= 0) {
1025 if (strat == 2) {
1026 *eb_sel = pin;
1028 sprintf(neko_log_buf, "Set by env : 2 (KSTEP, %d elem/block)",
1029 NEKO_EB_SEL(LX, pin));
1030 } else {
1031 *nwf_sel = pin;
1033 sprintf(neko_log_buf, "Set by env : 3 (MFMA %s, %d wf, %d elem/blk)",
1035 }
1038 return strat;
1039 }
1040
1041 if (strat) {
1042 sprintf(neko_log_buf, "Set by env : %d (%s)", strat, env_value);
1044 }
1045
1046 /* Formulations the sweep considers, see NEKO_TUNE_FOR(). NEKO_MFMA_TUNE
1047 keeps the matrix core variant out of an unpinned sweep, but naming it
1048 explicitly still measures it */
1049 const bool try_kstep = (strat == 0 || strat == 2);
1050 const bool try_mfma = mfma && ((strat == 3) ||
1051 (strat == 0 && neko_mfma_sweep()));
1052
1053 /* With neither the blocking sweep nor a matrix core variant there is one
1054 candidate, which is what these kernels have always run */
1055 if (!sweep && !try_mfma) {
1057 sprintf(neko_log_buf, "Vector Ax : %d elem/block (untuned)",
1058 NEKO_EB_SEL(LX, 0));
1061 return 2;
1062 }
1063
1066
1067 /* Verify every candidate against the reference formulation on a synthetic
1068 input before anything is timed, see neko_tune_verify_begin() in
1069 elem_block_tune.h. A candidate that does not reproduce it is reported
1070 and dropped from the comparison below. */
1071 neko_tune_rej_t rej2 = {{0}}, rej3 = {{0}};
1072 {
1074 real *vouts[] = { (real *) au, (real *) av, (real *) aw };
1075 void **vins[] = { &u, &v, &w };
1076 if (neko_tune_verify_begin(&vf, vouts, 3, vins, 3,
1077 (*nelv) * LX * LX * LX, stream)) {
1078 sprintf(neko_log_buf, "Verify : rel tol %.1e, synthetic input",
1079 vf.tol);
1082 neko_tune_verify_ref(&vf, stream);
1085 }
1088 }
1089 neko_tune_verify_end(&vf, stream);
1090 } else {
1091 sprintf(neko_log_buf, "Verify : %s", neko_tune_verify_on() ?
1092 "skipped, no memory for it" : "off (NEKO_TUNE_VERIFY=0)");
1094 }
1095 }
1096
1097 /* Warm every variant before timing anything, see tune() */
1098 for (int i = 0; i < NEKO_TUNE_WARMUP; i++) {
1101 }
1104 }
1105 }
1106
1107 /* Interleaved rounds, best time per variant, see tune() */
1108 for (int r = 0; r < rounds; r++) {
1111 }
1114 }
1115 }
1116
1117 /* Candidates the verification pass rejected drop out here, after the
1118 timing, so the sweep's own bookkeeping is untouched */
1121
1124
1127 *eb_sel = best2;
1128 *nwf_sel = best3;
1129
1130 /* The mfma variant joins the comparison only where it exists, its
1131 candidates are left at NEKO_TUNE_INIT otherwise */
1132 retval = (time3[best3] < time2[best2]) ? 3 : 2;
1133
1136
1137 /* The tuner stands in for a real Ax evaluation, and the variants do not
1138 sum in the same order, so leave the output of the chosen kernel in
1139 au, av and aw */
1140 if (retval == 2) {
1142 sprintf(neko_log_buf, "Chose : 2 (KSTEP, %d elem/block)",
1143 NEKO_EB_SEL(LX, best2));
1144 } else {
1146 sprintf(neko_log_buf, "Chose : 3 (MFMA %s, %d wf, %d elem/blk)",
1149 }
1152 return retval;
1153}
1154
1155/* Padded variant of tune_vector(), for the orders whose kstep kernel stages
1156 with a padded stride. The matrix core variant is the same either way */
1157template < const int LX >
1158int tune_vector_padded(void *au, void *av, void *aw,
1159 void *u, void *v, void *w,
1160 void *dx, void *dy, void *dz, void *h1,
1161 void *g11, void *g22, void *g33, void *g12,
1162 void *g13, void *g23, int *nelv, int *lx, int *eb_sel,
1163 int *nwf_sel) {
1166 int best2 = 0;
1168 int best3 = 0;
1169 const int rounds = neko_tune_rounds();
1170 const int iters = neko_tune_iters();
1171 const int sweep = neko_eb_sweep();
1172 /* Candidates of the kstep sweep, one -- the unblocked shape -- when the
1173 elements per block sweep is off */
1174 const int eb_cand = sweep ? NEKO_EB_CANDIDATES : 1;
1175 /* Candidates of the matrix core sweep, see neko_mfma_candidates() */
1176 const int mfma_cand = neko_mfma_candidates();
1177 /* Geometry pinned by each formulation's own variable, -1 to sweep it */
1178 const int eb_pin = neko_eb_pin();
1179 const int nwf_pin = neko_mfma_pin();
1180 /* Formulation pinned by NEKO_AUTOTUNE, as the identifier this returns */
1181 int strat = 0;
1182 /* Hardware capability, which the explicit NEKO_AUTOTUNE=MFMA pin needs */
1183 const bool mfma = mfma_lx_supported<LX>() && hip_have_mfma();
1184 int retval;
1185
1186 for (int c = 0; c < NEKO_EB_CANDIDATES; c++) {
1187 time2[c] = NEKO_TUNE_INIT;
1188 }
1189 for (int c = 0; c < NEKO_MFMA_CANDIDATES; c++) {
1190 time3[c] = NEKO_TUNE_INIT;
1191 }
1192
1193 const hipStream_t stream = (hipStream_t) glb_cmd_queue;
1194
1195 char *env_value = NULL;
1196 char neko_log_buf[80];
1197
1198 env_value = getenv("NEKO_AUTOTUNE");
1199
1200 sprintf(neko_log_buf, "Autotune Ax vector (lx: %d)", *lx);
1202
1203 *eb_sel = 0;
1204 *nwf_sel = 0;
1205
1206 /* NEKO_AUTOTUNE names a formulation and nothing more, see tune() */
1207 if (env_value) {
1208 if ( !strcmp(env_value, "KSTEP") || !strcmp(env_value, "1D") ) {
1209 /* No 1d variant here, so either pin lands on kstep */
1210 strat = 2;
1211 } else if ( !strcmp(env_value, "MFMA") ) {
1212 if (mfma) {
1213 strat = 3;
1214 } else {
1215 sprintf(neko_log_buf, "MFMA strategy not available for this config");
1217 }
1218 } else {
1219 sprintf(neko_log_buf, "Invalid value set for NEKO_AUTOTUNE");
1221 }
1222 }
1223
1224 /* Formulation and geometry both pinned leaves nothing to measure */
1225 const int pin = (strat == 2) ? eb_pin : (strat == 3) ? nwf_pin : -1;
1226
1227 if (pin >= 0) {
1228 if (strat == 2) {
1229 *eb_sel = pin;
1231 sprintf(neko_log_buf, "Set by env : 2 (KSTEP, %d elem/block)",
1232 NEKO_EB_SEL(LX, pin));
1233 } else {
1234 *nwf_sel = pin;
1236 sprintf(neko_log_buf, "Set by env : 3 (MFMA %s, %d wf, %d elem/blk)",
1238 }
1241 return strat;
1242 }
1243
1244 if (strat) {
1245 sprintf(neko_log_buf, "Set by env : %d (%s)", strat, env_value);
1247 }
1248
1249 /* Formulations the sweep considers, see NEKO_TUNE_FOR(). NEKO_MFMA_TUNE
1250 keeps the matrix core variant out of an unpinned sweep, but naming it
1251 explicitly still measures it */
1252 const bool try_kstep = (strat == 0 || strat == 2);
1253 const bool try_mfma = mfma && ((strat == 3) ||
1254 (strat == 0 && neko_mfma_sweep()));
1255
1256 /* One candidate, see tune_vector() */
1257 if (!sweep && !try_mfma) {
1259 sprintf(neko_log_buf, "Vector Ax : %d elem/block (untuned)",
1260 NEKO_EB_SEL(LX, 0));
1263 return 2;
1264 }
1265
1268
1269 /* Verify every candidate against the reference formulation on a synthetic
1270 input before anything is timed, see neko_tune_verify_begin() in
1271 elem_block_tune.h. A candidate that does not reproduce it is reported
1272 and dropped from the comparison below. */
1273 neko_tune_rej_t rej2 = {{0}}, rej3 = {{0}};
1274 {
1276 real *vouts[] = { (real *) au, (real *) av, (real *) aw };
1277 void **vins[] = { &u, &v, &w };
1278 if (neko_tune_verify_begin(&vf, vouts, 3, vins, 3,
1279 (*nelv) * LX * LX * LX, stream)) {
1280 sprintf(neko_log_buf, "Verify : rel tol %.1e, synthetic input",
1281 vf.tol);
1284 neko_tune_verify_ref(&vf, stream);
1287 "KSTEP");
1288 }
1291 }
1292 neko_tune_verify_end(&vf, stream);
1293 } else {
1294 sprintf(neko_log_buf, "Verify : %s", neko_tune_verify_on() ?
1295 "skipped, no memory for it" : "off (NEKO_TUNE_VERIFY=0)");
1297 }
1298 }
1299
1300 /* Warm every variant before timing anything, see tune() */
1301 for (int i = 0; i < NEKO_TUNE_WARMUP; i++) {
1304 }
1307 }
1308 }
1309
1310 /* Interleaved rounds, best time per variant, see tune() */
1311 for (int r = 0; r < rounds; r++) {
1314 }
1317 }
1318 }
1319
1320 /* Candidates the verification pass rejected drop out here, after the
1321 timing, so the sweep's own bookkeeping is untouched */
1324
1327
1330 *eb_sel = best2;
1331 *nwf_sel = best3;
1332
1333 /* The mfma variant joins the comparison only where it exists, its
1334 candidates are left at NEKO_TUNE_INIT otherwise */
1335 retval = (time3[best3] < time2[best2]) ? 3 : 2;
1336
1339
1340 /* Leave the output of the chosen kernel in au, av and aw, see
1341 tune_vector() */
1342 if (retval == 2) {
1344 sprintf(neko_log_buf, "Chose : 2 (KSTEP, %d elem/block)",
1345 NEKO_EB_SEL(LX, best2));
1346 } else {
1348 sprintf(neko_log_buf, "Chose : 3 (MFMA %s, %d wf, %d elem/blk)",
1351 }
1354 return retval;
1355}
int tune_padded(void *w, void *u, void *dx, void *dy, void *dz, void *dxt, void *dyt, void *dzt, void *h1, void *g11, void *g22, void *g33, void *g12, void *g13, void *g23, int *nelv, int *lx, int *eb_sel, int *ch_sel, int *nwf_sel)
Definition ax_helm.hip:706
#define CASE_VECTOR(LX)
#define CASE_VECTOR_MFMA_SEL(LX, SEL)
#define CASE_KSTEP_SEL(LX, SEL)
#define CASE(LX)
void hip_ax_helm_vector_part2(void *au, void *av, void *aw, void *u, void *v, void *w, void *h2, void *B, int *n)
Definition ax_helm.hip:440
#define CASE_1D_SEL(LX, SEL)
#define CASE_VECTOR_KSTEP(LX, C)
#define CASE_MFMA_SEL(LX, SEL)
#define CASE_PADDED(LX)
#define CASE_KSTEP_PADDED_SEL(LX, SEL)
#define CASE_LARGE(LX)
void hip_ax_helm_vector(void *au, void *av, void *aw, void *u, void *v, void *w, void *dx, void *dy, void *dz, void *dxt, void *dyt, void *dzt, void *h1, void *g11, void *g22, void *g33, void *g12, void *g13, void *g23, int *nelv, int *lx)
Definition ax_helm.hip:284
void hip_ax_helm(void *w, void *u, void *dx, void *dy, void *dz, void *dxt, void *dyt, void *dzt, void *h1, void *g11, void *g22, void *g33, void *g12, void *g13, void *g23, int *nelv, int *lx)
Definition ax_helm.hip:82
#define CASE_LARGE_PADDED(LX)
int tune_vector(void *au, void *av, void *aw, void *u, void *v, void *w, void *dx, void *dy, void *dz, void *h1, void *g11, void *g22, void *g33, void *g12, void *g13, void *g23, int *nelv, int *lx, int *eb_sel, int *nwf_sel)
Definition ax_helm.hip:956
#define CASE_VECTOR_KSTEP_PADDED(LX, C)
#define CASE_VECTOR_KSTEP_SEL(LX, SEL)
#define CASE_VECTOR_PADDED(LX)
#define CASE_VECTOR_KSTEP_PADDED_SEL(LX, SEL)
int tune(void *w, void *u, void *dx, void *dy, void *dz, void *dxt, void *dyt, void *dzt, void *h1, void *g11, void *g22, void *g33, void *g12, void *g13, void *g23, int *nelv, int *lx, int *eb_sel, int *ch_sel, int *nwf_sel)
Definition ax_helm.hip:458
int tune_vector_padded(void *au, void *av, void *aw, void *u, void *v, void *w, void *dx, void *dy, void *dz, void *h1, void *g11, void *g22, void *g33, void *g12, void *g13, void *g23, int *nelv, int *lx, int *eb_sel, int *nwf_sel)
Definition ax_helm.hip:1158
__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 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 T *__restrict__ T *__restrict__ aw
__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 T *__restrict__ T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ w
__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 *__restrict__ const int nelv
const int i
__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__ dz
__global__ void const T *__restrict__ const T *__restrict__ dx
__global__ void const T *__restrict__ u
__global__ void T *__restrict__ av
__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__ const T *__restrict__ const T *__restrict__ const T *__restrict__ g33
__global__ void T *__restrict__ T *__restrict__ const T *__restrict__ const T *__restrict__ v
__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__ const T *__restrict__ const T *__restrict__ h1
__global__ void const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dyt
__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__ const T *__restrict__ const T *__restrict__ const T *__restrict__ const T *__restrict__ dxt
#define NEKO_CHUNKS_CANDIDATES
Definition elem_block.h:125
#define NEKO_EB_CANDIDATES
Definition elem_block.h:63
#define NEKO_EB_SEL(LX, SEL)
Definition elem_block.h:108
#define NEKO_CHUNKS_SEL(LX, SEL)
Definition elem_block.h:147
static int neko_chunks_pin()
#define NEKO_TUNE_TIME(T, LAUNCH, LX, C, ITERS)
static int neko_tune_rounds()
static int neko_eb_pin()
#define NEKO_TUNE_LOG(LX, T1, T2)
#define NEKO_TUNE_INIT
#define NEKO_TUNE_BEST(T, BEST, N)
static int neko_tune_iters()
#define NEKO_TUNE_FOR(C, ON, PIN, N)
static int neko_eb_sweep()
#define NEKO_TUNE_WARMUP
double real
#define HIP_CHECK(err)
Definition check.h:8
static void neko_tune_verify_ref(neko_tune_verify_t *v, hipStream_t stream)
#define NEKO_TUNE_VERIFY_CAND(VF, REJ, LAUNCH, LX, C, NAME)
static void neko_tune_verify_end(neko_tune_verify_t *v, hipStream_t stream)
static int neko_tune_verify_on()
static int neko_tune_verify_begin(neko_tune_verify_t *v, real **outs, const int nout, void ***ins, const int nin, const int n, hipStream_t stream)
#define NEKO_TUNE_APPLY_REJ(T, REJ, N)
#define NEKO_TUNE_LOG_KSTEP(LX, T2)
#define NEKO_TUNE_LOG_MFMA_VEC(LX, T3)
#define NEKO_TUNE_LOG_MFMA(LX, T3)
static const char * mfma_tile_name(const int c)
#define NEKO_MFMA_CANDIDATES
static int neko_mfma_pin()
static int neko_mfma_candidates()
static bool hip_have_mfma()
#define NEKO_MFMA_NWF(C)
#define NEKO_MFMA_EB(LX, C)
static int neko_mfma_sweep()
void log_error(char *msg)
void log_message(char *msg)
void log_end_section()
void log_section(char *msg)