Cholla 3.0.1-dev
Cholla - Massively parallel hydro on GPUs
Loading...
Searching...
No Matches
gpu.hpp
1#pragma once
2
3#include <cassert>
4#include <cstdio>
5#include <cstdlib>
6#include <experimental/source_location>
7#include <iostream>
8
9#include "../utils/error_handling.h"
10
11#ifdef O_HIP
12
13 #include <hip/hip_runtime.h>
14
15 #include <hip/hip_cooperative_groups.h>
16
17 #if defined(PARIS) || defined(PARIS_GALACTIC)
18
19 #include <hipfft.h>
20
21 #endif // CUFFT PARIS PARIS_GALACTIC
22
23 #if !defined(HIP_VERSION) || (HIP_VERSION < 40200000)
24 // here, we are enforcing the requirement that HIP is version 4.2 or newer
25 // -> this check picks 4.2 because that's when the `HIP_VERSION` macro was first provided.
26 // This fact and the format of `HIP_VERSION` are described here:
27 // https://rocm.docs.amd.com/projects/HIP/en/docs-5.7.1/user_guide/faq.html#how-can-i-know-the-version-of-hip
28 // -> if we really want to add support for older HIP versions, we may need to compile test
29 // programs to query version numbers as part of the build-systems. But that seems
30 // unnecessary since, as of Nov 2025, AMD doesn't seem to document versions before 5.0
31 // -> in practice, I suspect we probably use some features that require versions of HIP
32 // released some time after 4.2 (ideally, we would update the HIP_VERSION requirement
33 // to reflect that)
34
35 #error "The current version of HIP is too old"
36 #endif
37
38 #define WARPSIZE 64
39static constexpr int maxWarpsPerBlock = 1024 / WARPSIZE;
40
41 #define CUFFT_D2Z HIPFFT_D2Z
42 #define CUFFT_FORWARD HIPFFT_FORWARD
43 #define CUFFT_INVERSE HIPFFT_BACKWARD
44 #define CUFFT_Z2D HIPFFT_Z2D
45 #define CUFFT_Z2Z HIPFFT_Z2Z
46 #define CUFFT_SUCCESS HIPFFT_SUCCESS
47 #define cufftResult_t hipfftResult_t
48
49 #define cudaDeviceSynchronize hipDeviceSynchronize
50 #define cudaError hipError_t
51 #define cudaError_t hipError_t
52 #define cudaErrorInsufficientDriver hipErrorInsufficientDriver
53 #define cudaErrorNoDevice hipErrorNoDevice
54 #define cudaEvent_t hipEvent_t
55 #define cudaEventCreate hipEventCreate
56 #define cudaEventElapsedTime hipEventElapsedTime
57 #define cudaEventRecord hipEventRecord
58 #define cudaEventSynchronize hipEventSynchronize
59 #define cudaFree hipFree
60 #define cudaFreeHost hipHostFree
61 #define cudaGetDevice hipGetDevice
62 #define cudaGetDeviceCount hipGetDeviceCount
63 #define cudaGetErrorString hipGetErrorString
64 #define cudaGetLastError hipGetLastError
65 #define cudaHostAlloc hipHostMalloc
66 #define cudaHostAllocDefault hipHostMallocDefault
67 #define cudaMalloc hipMalloc
68 #define cudaMemcpy hipMemcpy
69 #define cudaMemcpyAsync hipMemcpyAsync
70 #define cudaMemcpyPeer hipMemcpyPeer
71 #define cudaMemcpyDeviceToHost hipMemcpyDeviceToHost
72 #define cudaMemcpyDeviceToDevice hipMemcpyDeviceToDevice
73 #define cudaMemcpyHostToDevice hipMemcpyHostToDevice
74 #define cudaMemGetInfo hipMemGetInfo
75 #define cudaMemset hipMemset
76 #define cudaReadModeElementType hipReadModeElementType
77 #define cudaSetDevice hipSetDevice
78 #define cudaSuccess hipSuccess
79 #define cudaDeviceProp hipDeviceProp_t
80 #define cudaGetDeviceProperties hipGetDeviceProperties
81 #define cudaPointerAttributes hipPointerAttribute_t
82 #define cudaPointerGetAttributes hipPointerGetAttributes
83 #define cudaOccupancyMaxPotentialBlockSize hipOccupancyMaxPotentialBlockSize
84 #define cudaDeviceGetAttribute hipDeviceGetAttribute
85 #define cudaDevAttrCooperativeLaunch hipDeviceAttributeCooperativeLaunch
86 #define cudaOccupancyMaxActiveBlocksPerMultiprocessor hipOccupancyMaxActiveBlocksPerMultiprocessor
87 #define cudaLaunchCooperativeKernel hipLaunchCooperativeKernel
88 #define cudaMemGetInfo hipMemGetInfo
89 #define cudaDeviceGetPCIBusId hipDeviceGetPCIBusId
90 #define cudaPeekAtLastError hipPeekAtLastError
91 #define cudaFuncAttributes hipFuncAttributes
92 #define cudaFuncGetAttributes hipFuncGetAttributes
93
94 // Texture definitions
95 #define cudaArray hipArray
96 #define cudaMallocArray hipMallocArray
97 #define cudaFreeArray hipFreeArray
98 #define cudaMemcpyToArray hipMemcpyToArray
99 #define cudaMemcpy2DToArray hipMemcpy2DToArray
100
101 #define cudaTextureObject_t hipTextureObject_t
102 #define cudaCreateTextureObject hipCreateTextureObject
103 #define cudaDestroyTextureObject hipDestroyTextureObject
104 #define cudaGetTextureObjectResourceDesc hipGetTextureObjectResourceDesc
105
106 #define cudaChannelFormatDesc hipChannelFormatDesc
107 #define cudaCreateChannelDesc hipCreateChannelDesc
108 #define cudaChannelFormatKindFloat hipChannelFormatKindFloat
109
110 #define cudaResourceDesc hipResourceDesc
111 #define cudaResourceTypeArray hipResourceTypeArray
112 #define cudaTextureDesc hipTextureDesc
113 #define cudaAddressModeClamp hipAddressModeClamp
114 #define cudaFilterModeLinear hipFilterModeLinear
115 #define cudaFilterModePoint hipFilterModePoint
116 // Texture Definitions
117 #define cudaPointerAttributes hipPointerAttribute_t
118 #define cudaPointerGetAttributes hipPointerGetAttributes
119
120 // FFT definitions
121 #define cufftDestroy hipfftDestroy
122 #define cufftDoubleComplex hipfftDoubleComplex
123 #define cufftDoubleReal hipfftDoubleReal
124 #define cufftExecD2Z hipfftExecD2Z
125 #define cufftExecZ2D hipfftExecZ2D
126 #define cufftExecZ2Z hipfftExecZ2Z
127 #define cufftHandle hipfftHandle
128 #define cufftPlan3d hipfftPlan3d
129 #define cufftPlanMany hipfftPlanMany
130
131 #define curandStateMRG32k3a_t hiprandStateMRG32k3a_t
132 #define curand_init hiprand_init
133 #define curand hiprand
134 #define curand_poisson hiprand_poisson
135
136#else // not O_HIP
137
138 #include <cooperative_groups.h>
139 #include <cuda_runtime.h>
140
141 #if defined(PARIS) || defined(PARIS_GALACTIC)
142
143 #include <cufft.h>
144
145 #endif // defined(PARIS) || defined(PARIS_GALACTIC)
146
147 #define WARPSIZE 32
148static constexpr int maxWarpsPerBlock = 1024 / WARPSIZE;
149 #define hipLaunchKernelGGL(F, G, B, M, S, ...) F<<<G, B, M, S>>>(__VA_ARGS__)
150 #define __shfl_down(...) __shfl_down_sync(0xFFFFFFFF, __VA_ARGS__)
151
152// Used to Wrap template kernels with more than one parameter in this to avoid errors. This is present in the HIP
153// runtime but not the CUDA runtime
154 #define HIP_KERNEL_NAME(...) __VA_ARGS__
155#endif // O_HIP
156
157#define GPU_MAX_THREADS 256
158
166inline void Format_GPU_Error_Check_Err_(cudaError_t code, bool abort, std::experimental::source_location location)
167{
168 // this function should ALWAYS be compiled, (regardless of whether DISABLE_GPU_ERROR_CHECKING is
169 // defined or not). We will instead conditionally compile calls to this of this function based on
170 // whether DISABLE_GPU_ERROR_CHECKING is defined.
171
172 if (code != cudaSuccess) {
173 std::cout << "GPU_Error_Check: Failed at "
174 << "Line: " << location.line() << ", File: " << location.file_name()
175 << ", Function: " << location.function_name() << ", with code: " << cudaGetErrorString(code) << std::endl;
176 if (abort) {
177 chexit(code);
178 }
179 }
180}
181
210inline void GPU_Error_Check(cudaError_t code = cudaPeekAtLastError(), bool abort = true,
211 std::experimental::source_location location = std::experimental::source_location::current())
212{
213 // first, we check the argument passed into this function
214 // - earlier versions of this function did not perform this check.
215 // - as noted up in the docstring, it's extremely important to perform this check in addition to the next
216 // check because the next check won't identify cases where the kernel fails to launch
217 // - there's basically no reason to disable this check (it is extremely cheap)
218 if (code != cudaSuccess) Format_GPU_Error_Check_Err_(code, abort, location);
219
220#ifndef DISABLE_GPU_ERROR_CHECKING
221 // wait for any kernels being evaluated to finish and check if any errors arose in the process
222 code = cudaDeviceSynchronize();
223 if (code != cudaSuccess) Format_GPU_Error_Check_Err_(code, abort, location);
224#endif // DISABLE_GPU_ERROR_CHECKING
225}
226
227#if defined(PARIS) || defined(PARIS_GALACTIC)
235inline void GPU_Error_Check(cufftResult_t code, bool abort = true,
236 std::experimental::source_location location = std::experimental::source_location::current())
237{
238 #ifndef DISABLE_GPU_ERROR_CHECKING
239 // Check the code
240 if (code != CUFFT_SUCCESS) {
241 std::cout << "GPU_Error_Check: Failed at "
242 << "Line: " << location.line() << ", File: " << location.file_name()
243 << ", Function: " << location.function_name() << ", with FFT code: " << code << std::endl;
244 if (abort) {
245 chexit(code);
246 }
247 }
248 #endif // DISABLE_GPU_ERROR_CHECKING
249}
250#endif // defined(PARIS) || defined(PARIS_GALACTIC)
251
252#if defined(__CUDACC__) || defined(__HIPCC__)
253
254template <typename F>
255__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun0(const int n0, const F f)
256{
257 const int i0 = blockIdx.x * blockDim.x + threadIdx.x;
258 if (i0 < n0) {
259 f(i0);
260 }
261}
262
263template <typename F>
264void gpuFor(const int n0, const F f)
265{
266 if (n0 <= 0) {
267 return;
268 }
269 const int b0 = (n0 + GPU_MAX_THREADS - 1) / GPU_MAX_THREADS;
270 const int t0 = (n0 + b0 - 1) / b0;
271 gpuRun0<<<b0, t0>>>(n0, f);
272 GPU_Error_Check();
273}
274
275template <typename F>
276__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun0x2(const F f)
277{
278 const int i0 = threadIdx.y;
279 const int i1 = threadIdx.x;
280 f(i0, i1);
281}
282
283template <typename F>
284__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun1x1(const F f)
285{
286 const int i0 = blockIdx.x;
287 const int i1 = threadIdx.x;
288 f(i0, i1);
289}
290
291template <typename F>
292__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun2x0(const int n1, const F f)
293{
294 const int i0 = blockIdx.y;
295 const int i1 = blockIdx.x * blockDim.x + threadIdx.x;
296 if (i1 < n1) {
297 f(i0, i1);
298 }
299}
300
301template <typename F>
302void gpuFor(const int n0, const int n1, const F f)
303{
304 if ((n0 <= 0) || (n1 <= 0)) {
305 return;
306 }
307 const long nl01 = long(n0) * long(n1);
308 assert(nl01 < long(INT_MAX));
309
310 if (n1 > GPU_MAX_THREADS) {
311 const int b1 = (n1 + GPU_MAX_THREADS - 1) / GPU_MAX_THREADS;
312 const int t1 = (n1 + b1 - 1) / b1;
313 gpuRun2x0<<<dim3(b1, n0), dim3(t1)>>>(n1, f);
314 GPU_Error_Check();
315 } else if (nl01 > GPU_MAX_THREADS) {
316 gpuRun1x1<<<n0, n1>>>(f);
317 GPU_Error_Check();
318 } else {
319 gpuRun0x2<<<1, dim3(n1, n0)>>>(f);
320 GPU_Error_Check();
321 }
322}
323
324template <typename F>
325__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun0x3(const F f)
326{
327 const int i0 = threadIdx.z;
328 const int i1 = threadIdx.y;
329 const int i2 = threadIdx.x;
330 f(i0, i1, i2);
331}
332
333template <typename F>
334__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun1x2(const F f)
335{
336 const int i0 = blockIdx.x;
337 const int i1 = threadIdx.y;
338 const int i2 = threadIdx.x;
339 f(i0, i1, i2);
340}
341
342template <typename F>
343__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun2x1(const F f)
344{
345 const int i0 = blockIdx.y;
346 const int i1 = blockIdx.x;
347 const int i2 = threadIdx.x;
348 f(i0, i1, i2);
349}
350
351template <typename F>
352__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun3x0(const int n2, const F f)
353{
354 const int i0 = blockIdx.z;
355 const int i1 = blockIdx.y;
356 const int i2 = blockIdx.x * blockDim.x + threadIdx.x;
357 if (i2 < n2) {
358 f(i0, i1, i2);
359 }
360}
361
385template <typename F>
386void gpuFor(const int n0, const int n1, const int n2, const F f)
387{
388 if ((n0 <= 0) || (n1 <= 0) || (n2 <= 0)) {
389 return;
390 }
391 const long nl12 = long(n1) * long(n2);
392 const long nl012 = long(n0) * nl12;
393 assert(nl012 < long(INT_MAX));
394
395 if (n2 > GPU_MAX_THREADS) {
396 const int b2 = (n2 + GPU_MAX_THREADS - 1) / GPU_MAX_THREADS;
397 const int t2 = (n2 + b2 - 1) / b2;
398 gpuRun3x0<<<dim3(b2, n1, n0), t2>>>(n2, f);
399 GPU_Error_Check();
400 } else if (nl12 > GPU_MAX_THREADS) {
401 gpuRun2x1<<<dim3(n1, n0), n2>>>(f);
402 GPU_Error_Check();
403 } else if (nl012 > GPU_MAX_THREADS) {
404 gpuRun1x2<<<n0, dim3(n2, n1)>>>(f);
405 GPU_Error_Check();
406 } else {
407 gpuRun0x3<<<1, dim3(n2, n1, n0)>>>(f);
408 GPU_Error_Check();
409 }
410}
411
412template <typename F>
413__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun1x3(const F f)
414{
415 const int i0 = blockIdx.x;
416 const int i1 = threadIdx.z;
417 const int i2 = threadIdx.y;
418 const int i3 = threadIdx.x;
419 f(i0, i1, i2, i3);
420}
421
422template <typename F>
423__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun2x2(const F f)
424{
425 const int i0 = blockIdx.y;
426 const int i1 = blockIdx.x;
427 const int i2 = threadIdx.y;
428 const int i3 = threadIdx.x;
429 f(i0, i1, i2, i3);
430}
431
432template <typename F>
433__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun3x1(const F f)
434{
435 const int i0 = blockIdx.z;
436 const int i1 = blockIdx.y;
437 const int i2 = blockIdx.x;
438 const int i3 = threadIdx.x;
439 f(i0, i1, i2, i3);
440}
441
442template <typename F>
443__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun4x0(const int n23, const int n3, const F f)
444{
445 const int i23 = blockIdx.x * blockDim.x + threadIdx.x;
446 if (i23 < n23) {
447 const int i0 = blockIdx.z;
448 const int i1 = blockIdx.y;
449 const int i2 = i23 / n3;
450 const int i3 = i23 % n3;
451 f(i0, i1, i2, i3);
452 }
453}
454
455template <typename F>
456void gpuFor(const int n0, const int n1, const int n2, const int n3, const F f)
457{
458 if ((n0 <= 0) || (n1 <= 0) || (n2 <= 0) || (n3 <= 0)) {
459 return;
460 }
461 const long n23_long = long(n2) * long(n3);
462 const long n123_long = long(n1) * n23_long;
463 assert(long(n0) * n123_long < long(INT_MAX));
464
465 const int n23 = int(n23_long);
466 const int n123 = int(n123_long);
467 if (n3 > GPU_MAX_THREADS) {
468 const int b23 = (n23 + GPU_MAX_THREADS - 1) / GPU_MAX_THREADS;
469 const int t23 = (n23 + b23 - 1) / b23;
470 gpuRun4x0<<<dim3(b23, n1, n0), t23>>>(n23, n3, f);
471 GPU_Error_Check();
472 } else if (n23 > GPU_MAX_THREADS) {
473 gpuRun3x1<<<dim3(n2, n1, n0), n3>>>(f);
474 GPU_Error_Check();
475 } else if (n123 > GPU_MAX_THREADS) {
476 gpuRun2x2<<<dim3(n1, n0), dim3(n3, n2)>>>(f);
477 GPU_Error_Check();
478 } else {
479 gpuRun1x3<<<n0, dim3(n3, n2, n1)>>>(f);
480 GPU_Error_Check();
481 }
482}
483
484template <typename F>
485__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun2x3(const F f)
486{
487 const int i0 = blockIdx.y;
488 const int i1 = blockIdx.x;
489 const int i2 = threadIdx.z;
490 const int i3 = threadIdx.y;
491 const int i4 = threadIdx.x;
492 f(i0, i1, i2, i3, i4);
493}
494
495template <typename F>
496__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun3x2(const F f)
497{
498 const int i0 = blockIdx.z;
499 const int i1 = blockIdx.y;
500 const int i2 = blockIdx.x;
501 const int i3 = threadIdx.y;
502 const int i4 = threadIdx.x;
503 f(i0, i1, i2, i3, i4);
504}
505
506template <typename F>
507__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun4x1(const int n1, const F f)
508{
509 const int i01 = blockIdx.z;
510 const int i0 = i01 / n1;
511 const int i1 = i01 % n1;
512 const int i2 = blockIdx.y;
513 const int i3 = blockIdx.x;
514 const int i4 = threadIdx.x;
515 f(i0, i1, i2, i3, i4);
516}
517
518template <typename F>
519__global__ __launch_bounds__(GPU_MAX_THREADS) void gpuRun5x0(const int n1, const int n34, const int n4, const F f)
520{
521 const int i34 = blockIdx.x * blockDim.x + threadIdx.x;
522 if (i34 < n34) {
523 const int i01 = blockIdx.z;
524 const int i0 = i01 / n1;
525 const int i1 = i01 % n1;
526 const int i2 = blockIdx.y;
527 const int i3 = i34 / n4;
528 const int i4 = i34 % n4;
529 f(i0, i1, i2, i3, i4);
530 }
531}
532
533template <typename F>
534void gpuFor(const int n0, const int n1, const int n2, const int n3, const int n4, const F f)
535{
536 if ((n0 <= 0) || (n1 <= 0) || (n2 <= 0) || (n3 <= 0) || (n4 <= 0)) {
537 return;
538 }
539 const long nl01 = long(n0) * long(n1);
540 const long nl34 = long(n3) * long(n4);
541 assert(nl01 * long(n2) * nl34 < long(INT_MAX));
542
543 const int n34 = int(nl34);
544 if (n4 > GPU_MAX_THREADS) {
545 const int n01 = int(nl01);
546 const int b34 = (n34 + GPU_MAX_THREADS - 1) / GPU_MAX_THREADS;
547 const int t34 = (n34 + b34 - 1) / b34;
548 gpuRun5x0<<<dim3(b34, n2, n01), t34>>>(n1, n34, n4, f);
549 GPU_Error_Check();
550 } else if (n34 > GPU_MAX_THREADS) {
551 const int n01 = n0 * n1;
552 gpuRun4x1<<<dim3(n3, n2, n01), n4>>>(n1, f);
553 GPU_Error_Check();
554 } else if (n2 * n34 > GPU_MAX_THREADS) {
555 gpuRun3x2<<<dim3(n2, n1, n0), dim3(n4, n3)>>>(f);
556 GPU_Error_Check();
557 } else {
558 gpuRun2x3<<<dim3(n1, n0), dim3(n4, n3, n2)>>>(f);
559 GPU_Error_Check();
560 }
561}
562
576 #define GPU_LAMBDA [=] __device__
577
578#endif