Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
arch_device_hip.h
Go to the documentation of this file.
1#ifndef ARCH_DEVICE_HIP_H
2#define ARCH_DEVICE_HIP_H
3
4/* Include required headers */
5#include <hip/hip_runtime.h>
6#include <hipcub/hipcub.hpp>
7#include <hipcub/device/device_radix_sort.hpp>
8
9#include <omp.h>
10
11/* architecture-agnostic definitions for HIP */
12
13#define gpuGetLastError hipGetLastError
14#define gpuGetErrorString hipGetErrorString
15#define gpuPeekAtLastError hipPeekAtLastError
16
17#define gpuSetDevice hipSetDevice
18#define gpuGetDevice hipGetDevice
19#define gpuGetDeviceCount hipGetDeviceCount
20#define gpuGetDeviceProperties hipGetDeviceProperties
21#define gpuDeviceGetAttribute hipDeviceGetAttribute
22#define gpuDeviceSynchronize hipDeviceSynchronize
23#define gpuDeviceReset hipDeviceReset
24#define gpuCpuDeviceId hipCpuDeviceId
25#define gpuMemGetInfo hipMemGetInfo
26
27#define gpuDevAttrMaxBlocksPerMultiprocessor hipDeviceAttributeMaxBlocksPerMultiProcessor // This is not well defined on AMD
28
29#define gpuFree hipFree
30#define gpuFreeHost hipHostFree
31#define gpuFreeAsync(ptr,stream) hipFree(ptr)
32#define gpuMalloc hipMalloc
33#define gpuMallocHost hipHostMalloc
34#define gpuMallocAsync hipMallocAsync
35#define gpuMallocManaged hipMallocManaged
36#define gpuHostAlloc hipHostMalloc
37#define gpuHostAllocPortable hipHostAllocPortable
38#define gpuMemcpy hipMemcpy
39#define gpuMemcpyAsync hipMemcpyAsync
40#define gpuMemset hipMemset
41#define gpuMemsetAsync hipMemsetAsync
42
43#define gpuMemAdviseSetAccessedBy hipMemAdviseSetAccessedBy
44#define gpuMemAdviseSetPreferredLocation hipMemAdviseSetPreferredLocation
45#define gpuMemAttachSingle hipMemAttachSingle
46#define gpuMemAttachGlobal hipMemAttachGlobal
47#define gpuMemPrefetchAsync hipMemPrefetchAsync
48
49#define gpuStreamCreate hipStreamCreate
50#define gpuHostRegister hipHostRegister
51#define gpuHostRegisterPortable hipHostRegisterPortable
52
53#define gpuStreamDestroy hipStreamDestroy
54#define gpuStreamWaitEvent hipStreamWaitEvent
55#define gpuStreamSynchronize hipStreamSynchronize
56#define gpuStreamAttachMemAsync hipStreamAttachMemAsync
57#define gpuDeviceGetStreamPriorityRange hipDeviceGetStreamPriorityRange
58#define gpuStreamCreateWithPriority hipStreamCreateWithPriority
59#define gpuStreamDefault hipStreamDefault
60
61#define gpuEventCreate hipEventCreate
62#define gpuEventCreateWithFlags hipEventCreateWithFlags
63#define gpuEventDestroy hipEventDestroy
64#define gpuEventQuery hipEventQuery
65#define gpuEventRecord hipEventRecord
66#define gpuEventSynchronize hipEventSynchronize
67#define gpuEventElapsedTime hipEventElapsedTime
68
69/* driver_types */
70#define gpuError_t hipError_t
71#define gpuSuccess hipSuccess
72
73#define gpuStream_t hipStream_t
74#define gpuDeviceProp hipDeviceProp_t
75
76#define gpuEvent_t hipEvent_t
77#define gpuEventDefault hipEventDefault
78#define gpuEventBlockingSync hipEventBlockingSync
79#define gpuEventDisableTiming hipEventDisableTiming
80
81#define gpuMemcpyKind hipMemcpyKind
82#define gpuMemcpyDeviceToHost hipMemcpyDeviceToHost
83#define gpuMemcpyHostToDevice hipMemcpyHostToDevice
84#define gpuMemcpyDeviceToDevice hipMemcpyDeviceToDevice
85#define gpuMemcpyHostToHost hipMemcpyHostToHost
86#define gpuMemcpyToSymbol hipMemcpyToSymbol
87
88#define gpuKernelBallot(mask, input) __ballot(input)
89#define gpuKernelAny(mask, input) __any(input)
90#define gpuKernelShfl(input, source, mask) __shfl(input, source)
91#define gpuKernelShflDown(val, offset) __shfl_down(val, offset)
92#define gpuWarpSync() ((void)0) //do nothing
93
94/* Define architecture-specific macros */
95#define ARCH_LOOP_LAMBDA [=] __host__ __device__
96#define ARCH_INNER_BODY2(i, j, aggregate)
97#define ARCH_INNER_BODY3(i, j, k, aggregate)
98#define ARCH_INNER_BODY4(i, j, k, l, aggregate)
99
100/* Ensure printing of CUB GPU runtime errors to console */
101#define HIPCUB_STDERR
102
103/* Set HIP blocksize used for reductions */
104#define ARCH_BLOCKSIZE_R 512
105#define ARCH_BLOCKSIZE_R_SMALL 64
106
107/* values used by kernels */
108#ifndef GPUTHREADS
109#define GPUTHREADS (64)
110#endif
111#ifndef WARPSPERBLOCK
112#define WARPSPERBLOCK (16)
113#endif
114#define FULL_MASK 0xffffffffffffffff
115
116extern hipStream_t gpuStreamList[];
117
118/* Define the HIP error checking macro */
119#define CHK_ERR(err) (hip_error(err, __FILE__, __LINE__))
120inline static void hip_error(hipError_t err, const char *file, int line) {
121 if (err != hipSuccess) {
122 printf("\n\n%s in %s at line %d\n", hipGetErrorString(err), file, line);
123 exit(1);
124 }
125}
126
127/* Namespace for architecture-specific functions */
128namespace arch{
129
130/* Create auxiliary max atomic function for double types */
131 __device__ __forceinline__ static void atomicMax(double *address, double val2) {
132 unsigned long long ret = __double_as_longlong(*address);
133 while(val2 > __longlong_as_double(ret)) {
134 unsigned long long old = ret;
135 if((ret = atomicCAS((unsigned long long *)address, old, __double_as_longlong(val2))) == old) {
136 break;
137 }
138 }
139 }
140
141/* Create auxiliary min atomic function for double types */
142 __device__ __forceinline__ static void atomicMin(double *address, double val2) {
143 unsigned long long ret = __double_as_longlong(*address);
144 while(val2 < __longlong_as_double(ret)) {
145 unsigned long long old = ret;
146 if((ret = atomicCAS((unsigned long long *)address, old, __double_as_longlong(val2))) == old) {
147 break;
148 }
149 }
150 }
151
152/* Create auxiliary max atomic function for float types */
153 __device__ __forceinline__ static void atomicMax(float *address, float val2) {
154 unsigned long long ret = __double_as_longlong((double)*address);
155 while((double)val2 > __longlong_as_double(ret)) {
156 unsigned long long old = ret;
157 if((ret = atomicCAS((unsigned long long *)address, old, __double_as_longlong((double)val2))) == old) {
158 break;
159 }
160 }
161 }
162
163/* Create auxiliary min atomic function for float types */
164 __device__ __forceinline__ static void atomicMin(float *address, float val2) {
165 unsigned long long ret = __double_as_longlong((double)*address);
166 while((double)val2 < __longlong_as_double(ret)) {
167 unsigned long long old = ret;
168 if((ret = atomicCAS((unsigned long long *)address, old, __double_as_longlong((double)val2))) == old) {
169 break;
170 }
171 }
172 }
173
174/* Buffer class for making data available on device */
175 template <typename T>
176 class buf {
177 private:
178 T *ptr;
179 T *d_ptr;
180 uint bytes;
181 uint is_copy = 0;
182 uint thread_id = 0;
183
184 public:
185
186 void syncDeviceData(void){
187 CHK_ERR(hipMemcpyAsync(d_ptr, ptr, bytes, hipMemcpyHostToDevice, gpuStreamList[thread_id]));
188 }
189
190 void syncHostData(void){
191 CHK_ERR(hipMemcpyAsync(ptr, d_ptr, bytes, hipMemcpyDeviceToHost, gpuStreamList[thread_id]));
192 }
193
194 buf(T * const _ptr, uint _bytes) : ptr(_ptr), bytes(_bytes) {
195 thread_id = omp_get_thread_num();
196 CHK_ERR(hipMallocAsync(&d_ptr, bytes, gpuStreamList[thread_id]));
198 }
199
200 __host__ __device__ buf(const buf& u) :
201 ptr(u.ptr), d_ptr(u.d_ptr), bytes(u.bytes), is_copy(1), thread_id(u.thread_id) {}
202
203 __host__ ~buf(void){
204 if(!is_copy){
205 // syncHostData();
206#ifdef __HIP_DEVICE_COMPILE__
207 hipFreeAsync(d_ptr, gpuStreamList[thread_id]);
208#endif
209 }
210 }
211
212 __host__ __device__ T &operator [] (uint i) const {
213#ifdef __HIP_DEVICE_COMPILE__
214 return d_ptr[i];
215#else
216 return ptr[i];
217#endif
218 }
219 };
220
221/* A function to check and set the device mempool settings */
222 __host__ __forceinline__ static void device_mempool_check(uint64_t threshold_new) {
223 int device_id;
224 CHK_ERR(hipGetDevice(&device_id));
225 hipMemPool_t mempool;
226 CHK_ERR(hipDeviceGetDefaultMemPool(&mempool, device_id));
227 uint64_t threshold_old;
228 CHK_ERR(hipMemPoolGetAttribute(mempool, hipMemPoolAttrReleaseThreshold, &threshold_old));
229 if(threshold_new != threshold_old) {
230 CHK_ERR(hipMemPoolSetAttribute(mempool, hipMemPoolAttrReleaseThreshold, &threshold_new));
231 }
232 }
233
234/* Device function for memory allocation */
235 __host__ __forceinline__ static void* allocate(size_t bytes) {
236 void* ptr;
237 const uint thread_id = omp_get_thread_num();
238 device_mempool_check(UINT64_MAX);
239 CHK_ERR(hipMallocAsync(&ptr, bytes, gpuStreamList[thread_id]));
240 return ptr;
241 }
242
243 __host__ __forceinline__ static void* allocate(size_t bytes, hipStream_t stream) {
244 void* ptr;
245 device_mempool_check(UINT64_MAX);
246 CHK_ERR(hipMallocAsync(&ptr, bytes, stream));
247 return ptr;
248 }
249
250/* Device function for memory deallocation */
251 template <typename T>
252 __host__ __forceinline__ static void free(T* ptr) {
253 const uint thread_id = omp_get_thread_num();
254 CHK_ERR(hipFreeAsync(ptr, gpuStreamList[thread_id]));
255 }
256
257 template <typename T>
258 __host__ __forceinline__ static void free(T* ptr, hipStream_t stream) {
259 CHK_ERR(hipFreeAsync(ptr, stream));
260 }
261/* Host-to-device memory copy */
262 template <typename T>
263 __forceinline__ static void memcpy_h2d(T* dst, T* src, size_t bytes){
264 const uint thread_id = omp_get_thread_num();
265 CHK_ERR(hipMemcpyAsync(dst, src, bytes, hipMemcpyHostToDevice, gpuStreamList[thread_id]));
266 }
267
268 template <typename T>
269 __forceinline__ static void memcpy_h2d(T* dst, T* src, size_t bytes, hipStream_t stream){
270 CHK_ERR(hipMemcpyAsync(dst, src, bytes, hipMemcpyHostToDevice, stream));
271 }
272
273/* Device-to-host memory copy */
274 template <typename T>
275 __forceinline__ static void memcpy_d2h(T* dst, T* src, size_t bytes){
276 const uint thread_id = omp_get_thread_num();
277 CHK_ERR(hipMemcpyAsync(dst, src, bytes, hipMemcpyDeviceToHost, gpuStreamList[thread_id]));
278 }
279
280 template <typename T>
281 __forceinline__ static void memcpy_d2h(T* dst, T* src, size_t bytes, hipStream_t stream){
282 CHK_ERR(hipMemcpyAsync(dst, src, bytes, hipMemcpyDeviceToHost, stream));
283 }
284
285/* Register, ie, page-lock existing host allocations */
286 template <typename T>
287 __forceinline__ static void host_register(T* ptr, size_t bytes){
288 CHK_ERR(hipHostRegister(ptr, bytes, hipHostRegisterDefault));
289 }
290
291/* Unregister page-locked host allocations */
292 template <typename T>
293 __forceinline__ static void host_unregister(T* ptr){
294 CHK_ERR(hipHostUnregister(ptr));
295 }
296
297/* Specializations for lambda calls depending on the templated dimension */
298 template <typename Lambda, typename T>
299 __device__ __forceinline__ static void lambda_eval(const uint (&idx)[1], T * __restrict__ thread_data, Lambda loop_body) { loop_body(idx[0], thread_data); }
300
301 template <typename Lambda, typename T>
302 __device__ __forceinline__ static void lambda_eval(const uint (&idx)[2], T * __restrict__ thread_data, Lambda loop_body) { loop_body(idx[0], idx[1], thread_data); }
303
304 template <typename Lambda, typename T>
305 __device__ __forceinline__ static void lambda_eval(const uint (&idx)[3], T * __restrict__ thread_data, Lambda loop_body) { loop_body(idx[0], idx[1], idx[2], thread_data); }
306
307 template <typename Lambda, typename T>
308 __device__ __forceinline__ static void lambda_eval(const uint (&idx)[4], T * __restrict__ thread_data, Lambda loop_body) { loop_body(idx[0], idx[1], idx[2], idx[3], thread_data); }
309
310/* Get the index for the underlying dimension, and call the respective lambda wrapper */
311 template <uint NDim, typename Lambda, typename T>
312 __device__ __forceinline__ static void loop_eval(const uint idx_glob, const uint * __restrict__ lims, T * __restrict__ thread_data, Lambda loop_body) {
313 uint idx[NDim];
314 switch (NDim)
315 {
316 // Note: intended fall-through
317 case 4:
318 idx[3] = (idx_glob / (lims[0] * lims[1] * lims[2])) % lims[3];
319 case 3:
320 idx[2] = (idx_glob / (lims[0] * lims[1])) % lims[2];
321 case 2:
322 idx[1] = (idx_glob / lims[0]) % lims[1];
323 case 1:
324 idx[0] = idx_glob % lims[0];
325 break;
326 default:
327 assert( 0 && "incorrect reduction dimensions, abort!\n");
328 }
329 lambda_eval(idx, thread_data, loop_body);
330 }
331
332/* A general device kernel for reductions */
333 template <uint Blocksize, reduce_op Op, uint NDim, uint NReduStatic, typename Lambda, typename T>
334 __global__ static void __launch_bounds__(ARCH_BLOCKSIZE_R)
335 reduction_kernel(Lambda loop_body, const T * __restrict__ init_val, T * __restrict__ rslt, const uint * __restrict__ lims, const uint n_total, const uint n_redu_dynamic, T *thread_data_dynamic)
336 {
337 /* Get the global 1D thread index*/
338 const uint idx_glob = blockIdx.x * blockDim.x + threadIdx.x;
339
340 if (Op == reduce_op::null) {
341 T* thread_data = 0;
342 /* Check the loop limits and evaluate the loop body */
343 if (idx_glob < n_total) {
344 loop_eval<NDim>(idx_glob, lims, thread_data, loop_body);
345 }
346 return;
347 }
348
349 /* Specialize BlockReduce for a 1D block of Blocksize threads of type `T` */
350 typedef hipcub::BlockReduce<T, Blocksize, hipcub::BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY, 1, 1> BlockReduce;
351
352 /* Dynamic shared memory declaration */
353 extern __shared__ char temp_storage_dynamic[];
354
355 /* Static shared memory declaration */
356 constexpr uint size = NReduStatic ? NReduStatic : 1;
357 __shared__ typename BlockReduce::TempStorage temp_storage_static[size];
358
359 /* Assign a pointer to the shared memory (dynamic or static case) */
360 typename BlockReduce::TempStorage *temp_storage = NReduStatic ? temp_storage_static : (typename BlockReduce::TempStorage*) temp_storage_dynamic;
361
362 /* Static thread data declaration */
364
365 /* Assign a pointer to the thread data (dynamic or static case)*/
366 T *thread_data = NReduStatic ? thread_data_static : &thread_data_dynamic[n_redu_dynamic * idx_glob];
367
368 /* Get the number of reductions (may be known at compile time or not) */
369 const uint n_reductions = NReduStatic ? NReduStatic : n_redu_dynamic;
370
371 /* Set initial values */
372 for(uint i = 0; i < n_reductions; i++){
373 if (Op == reduce_op::sum) {
374 thread_data[i] = 0;
375 } else {
377 }
378 }
379
380 /* Check the loop limits and evaluate the loop body */
381 if (idx_glob < n_total) {
382 loop_eval<NDim>(idx_glob, lims, thread_data, loop_body);
383 }
384
385 /* Perform reductions */
386 for(uint i = 0; i < n_reductions; i++){
387 /* Compute the block-wide sum for thread 0 which stores it */
388 if(Op == reduce_op::sum){
389 T aggregate = BlockReduce(temp_storage[i]).Sum(thread_data[i]);
390 /* The first thread of each block stores the block-wide aggregate atomically */
391 if(threadIdx.x == 0) {
392 atomicAdd(&rslt[i], aggregate);
393 }
394 }
395 else if(Op == reduce_op::max){
396 T aggregate = BlockReduce(temp_storage[i]).Reduce(thread_data[i], hipcub::Max());
397 if(threadIdx.x == 0) {
398 atomicMax(&rslt[i], aggregate);
399 }
400 }
401 else if(Op == reduce_op::min){
402 T aggregate = BlockReduce(temp_storage[i]).Reduce(thread_data[i], hipcub::Min());
403 if(threadIdx.x == 0) {
404 atomicMin(&rslt[i], aggregate);
405 }
406 }
407 else
408 /* Other reduction operations are not supported - print an error message */
409 if(threadIdx.x == 0) {
410 printf("ERROR at %s:%d: Invalid reduction identifier \"Op\".", __FILE__, __LINE__);
411 }
412 }
413 }
414
415
416
417/* Parallel reduce driver function for the HIP reductions */
418 template <reduce_op Op, uint NReduStatic, uint NDim, typename Lambda, typename T>
419 __forceinline__ static void parallel_reduce_driver(const uint (&limits)[NDim], Lambda loop_body, T *sum, const uint n_redu_dynamic) {
420
421 /* Get the CPU thread id */
422#ifdef _OPENMP
423 const uint thread_id = omp_get_thread_num();
424#else
425 const uint thread_id = 0;
426#endif
427
428 /* Get the number of reductions (may be known at compile time or not) */
429 const uint n_reductions = NReduStatic ? NReduStatic : n_redu_dynamic;
430
431 /* Calculate the required size for the 1D kernel */
432 uint n_total = 1;
433 for(uint i = 0; i < NDim; i++) {
434 n_total *= limits[i];
435 }
436
437 /* Check the HIP default mempool settings and correct if wrong */
438 device_mempool_check(UINT64_MAX);
439
440 /* Create a device buffer to transfer the loop limits of each dimension to device */
441 uint* d_limits;
442 CHK_ERR(hipMallocAsync(&d_limits, NDim*sizeof(uint), gpuStreamList[thread_id]));
443 CHK_ERR(hipMemcpyAsync(d_limits, limits, NDim*sizeof(uint), hipMemcpyHostToDevice,gpuStreamList[thread_id]));
444
445 /* Simple action for non-reducing call */
446 if (Op == reduce_op::null) {
447 T *d_const_buf = 0;
448 T *d_buf = 0;
449 T *d_thread_data_dynamic = 0;
450 /* Set the kernel dimensions */
451 const uint blocksize = ARCH_BLOCKSIZE_R;
452 const uint gridsize = (n_total - 1 + blocksize) / blocksize;
453 /* Call the kernel (the number of reductions known at compile time) */
454 if(gridsize > 0) {
455 reduction_kernel<ARCH_BLOCKSIZE_R, Op, NDim, NReduStatic><<<gridsize, blocksize, 0, gpuStreamList[thread_id]>>>(loop_body, d_const_buf, d_buf, d_limits, n_total, n_reductions, d_thread_data_dynamic);
456 }
457 /* Check for kernel launch errors */
458 CHK_ERR(hipPeekAtLastError());
459 /* Synchronize after kernel call */
460 CHK_ERR(hipStreamSynchronize(gpuStreamList[thread_id]));
461 CHK_ERR(hipFreeAsync(d_limits, gpuStreamList[thread_id]));
462 return;
463 }
464
465 /* Create a device buffer for the reduction results */
466 T* d_buf;
467 CHK_ERR(hipMallocAsync(&d_buf, n_reductions*sizeof(T), gpuStreamList[thread_id]));
468 CHK_ERR(hipMemcpyAsync(d_buf, sum, n_reductions*sizeof(T), hipMemcpyHostToDevice, gpuStreamList[thread_id]));
469
470 /* Create a device buffer to transfer the initial values to device */
471 T* d_const_buf;
472 CHK_ERR(hipMallocAsync(&d_const_buf, n_reductions*sizeof(T), gpuStreamList[thread_id]));
473 CHK_ERR(hipMemcpyAsync(d_const_buf, d_buf, n_reductions*sizeof(T), hipMemcpyDeviceToDevice, gpuStreamList[thread_id]));
474
475 /* Call the reduction kernel with different arguments depending
476 * on if the number of reductions is known at the compile time
477 */
478 T* d_thread_data_dynamic = 0; // declared zero to suppress unitialized use warning
479 if(NReduStatic == 0) {
480 /* Get the cub temp storage sizes for the dynamic shared memory kernel argument */
481 constexpr auto cub_temp_storage_type_size = sizeof(typename hipcub::BlockReduce<T, ARCH_BLOCKSIZE_R, hipcub::BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY, 1, 1>::TempStorage);
482 constexpr auto cub_temp_storage_type_size_small = sizeof(typename hipcub::BlockReduce<T, ARCH_BLOCKSIZE_R_SMALL, hipcub::BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY, 1, 1>::TempStorage);
483 /* Query device properties */
484 int device_id;
485 CHK_ERR(hipGetDevice(&device_id));
486 hipDeviceProp_t deviceProp;
487 CHK_ERR(hipGetDeviceProperties(&deviceProp, device_id));
488 /* Make sure there is enough shared memory for the used block size */
489 uint blocksize;
490 size_t shared_mem_bytes_per_block_request;
491 if(n_reductions * cub_temp_storage_type_size <= deviceProp.sharedMemPerBlock){
492 blocksize = ARCH_BLOCKSIZE_R;
493 shared_mem_bytes_per_block_request = n_reductions * cub_temp_storage_type_size;
494 }
495 else if(n_reductions * cub_temp_storage_type_size_small <= deviceProp.sharedMemPerBlock){
496 blocksize = ARCH_BLOCKSIZE_R_SMALL;
497 shared_mem_bytes_per_block_request = n_reductions * cub_temp_storage_type_size_small;
498 }
499 else{
500 printf("The device %d (%s) does not have enough shared memory even for the small blocksize (%d)! The error occurred in %s at line %d\n", device_id, deviceProp.gcnArchName, ARCH_BLOCKSIZE_R_SMALL, __FILE__, __LINE__);
501 exit(1);
502 }
503 /* Set the kernel grid dimensions */
504 const uint gridsize = (n_total - 1 + blocksize) / blocksize;
505 /* Allocate memory for the thread data values */
506 CHK_ERR(hipMallocAsync(&d_thread_data_dynamic, n_reductions * blocksize * gridsize * sizeof(T), gpuStreamList[thread_id]));
507 /* Call the kernel (the number of reductions not known at compile time) */
508 if(gridsize > 0){
509 if(blocksize == ARCH_BLOCKSIZE_R){
510 reduction_kernel<ARCH_BLOCKSIZE_R, Op, NDim, 0><<<gridsize, blocksize, shared_mem_bytes_per_block_request, gpuStreamList[thread_id]>>>(loop_body, d_const_buf, d_buf, d_limits, n_total, n_reductions, d_thread_data_dynamic);
511 }
512 else if(blocksize == ARCH_BLOCKSIZE_R_SMALL){
513 reduction_kernel<ARCH_BLOCKSIZE_R_SMALL, Op, NDim, 0><<<gridsize, blocksize, shared_mem_bytes_per_block_request, gpuStreamList[thread_id]>>>(loop_body, d_const_buf, d_buf, d_limits, n_total, n_reductions, d_thread_data_dynamic);
514 }
515 else{
516 printf("The blocksize (%u) does not match with any of the predetermined block sizes! The error occurred in %s at line %d\n", blocksize, __FILE__, __LINE__);
517 exit(1);
518 }
519 }
520 /* Check for kernel launch errors */
521 CHK_ERR(hipPeekAtLastError());
522 /* Synchronize and free the thread data allocation */
523 CHK_ERR(hipStreamSynchronize(gpuStreamList[thread_id]));
524 CHK_ERR(hipFreeAsync(d_thread_data_dynamic, gpuStreamList[thread_id]));
525 }
526 else{
527 /* Set the kernel dimensions */
528 const uint blocksize = ARCH_BLOCKSIZE_R;
529 const uint gridsize = (n_total - 1 + blocksize) / blocksize;
530 /* Call the kernel (the number of reductions known at compile time) */
531 if(gridsize > 0) {
532 reduction_kernel<ARCH_BLOCKSIZE_R, Op, NDim, NReduStatic><<<gridsize, blocksize, 0, gpuStreamList[thread_id]>>>(loop_body, d_const_buf, d_buf, d_limits, n_total, n_reductions, d_thread_data_dynamic);
533 }
534 /* Check for kernel launch errors */
535 CHK_ERR(hipPeekAtLastError());
536 /* Synchronize after kernel call */
537 CHK_ERR(hipStreamSynchronize(gpuStreamList[thread_id]));
538 }
539 /* Copy the results back to host and free the allocated memory back to pool*/
540 CHK_ERR(hipMemcpyAsync(sum, d_buf, n_reductions*sizeof(T), hipMemcpyDeviceToHost, gpuStreamList[thread_id]));
541 CHK_ERR(hipFreeAsync(d_buf, gpuStreamList[thread_id]));
542 CHK_ERR(hipFreeAsync(d_const_buf, gpuStreamList[thread_id]));
543 CHK_ERR(hipFreeAsync(d_limits, gpuStreamList[thread_id]));
544 }
545}
546
547
548#endif // !ARCH_DEVICE_HIP_H
Binary file
Definition Dispersion.m:11
for i
Definition Dispersion.m:24
cudaStream_t gpuStreamList[]
Definition gpu_base.cpp:51
#define CHK_ERR(err)
#define ARCH_BLOCKSIZE_R_SMALL
#define ARCH_BLOCKSIZE_R
static void hip_error(hipError_t err, const char *file, int line)
__host__ ~buf(void)
void syncDeviceData(void)
__host__ __device__ T & operator[](uint i) const
void syncHostData(void)
__host__ __device__ buf(const buf &u)
buf(T *const _ptr, uint _bytes)
__device__ static __forceinline__ void atomicMin(double *address, double val2)
static __global__ void const T *__restrict__ T *__restrict__ const uint *__restrict__ const uint const uint n_redu_dynamic
__device__ static __forceinline__ void lambda_eval(const uint(&idx)[1], T *__restrict__ thread_data, Lambda loop_body)
static __forceinline__ void memcpy_d2h(T *dst, T *src, size_t bytes)
static __forceinline__ void parallel_reduce_driver(const uint(&limits)[NDim], Lambda loop_body, T *sum, const uint n_redu_dynamic)
constexpr uint size
static __forceinline__ void host_unregister(T *ptr)
static __global__ void const T *__restrict__ T *__restrict__ const uint *__restrict__ const uint n_total
static __global__ void const T *__restrict__ init_val
static __global__ void const T *__restrict__ T *__restrict__ const uint *__restrict__ const uint const uint T * thread_data_dynamic
__host__ static __forceinline__ void * allocate(size_t bytes)
T thread_data_static[size]
static __global__ void __launch_bounds__(ARCH_BLOCKSIZE_R) reduction_kernel(Lambda loop_body
static __global__ void const T *__restrict__ T *__restrict__ const uint *__restrict__ lims
static __forceinline__ void host_register(T *ptr, size_t bytes)
__shared__ BlockReduce::TempStorage temp_storage_static[size]
__host__ static __forceinline__ void device_mempool_check(uint64_t threshold_new)
__device__ static __forceinline__ void loop_eval(const uint idx_glob, const uint *__restrict__ lims, T *__restrict__ thread_data, Lambda loop_body)
BlockReduce::TempStorage * temp_storage
T * thread_data
static __global__ void const T *__restrict__ T *__restrict__ rslt
static __forceinline__ void memcpy_h2d(T *dst, T *src, size_t bytes)
uint32_t uint
__device__ static __forceinline__ void atomicMax(double *address, double val2)
__host__ static __forceinline__ void free(T *ptr)
cub::BlockReduce< T, Blocksize, cub::BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY, 1, 1 > BlockReduce
__shared__ char temp_storage_dynamic[]
const uint n_reductions