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