14#ifndef NANOVDB_UTIL_CUDA_UTIL_H_HAS_BEEN_INCLUDED
15#define NANOVDB_UTIL_CUDA_UTIL_H_HAS_BEEN_INCLUDED
18#include <cuda_runtime_api.h>
23#if 1 || defined(DEBUG) || defined(_DEBUG)
24 static inline void gpuAssert(cudaError_t code,
const char* file,
int line,
bool abort =
true)
26 if (code != cudaSuccess) {
27 fprintf(stderr,
"CUDA error %u: %s (%s:%d)\n",
unsigned(code), cudaGetErrorString(code), file, line);
29 if (abort) exit(code);
32 static inline void ptrAssert(
const void* ptr,
const char* msg,
const char* file,
int line,
bool abort =
true)
35 fprintf(stderr,
"NULL pointer error: %s %s %d\n", msg, file, line);
37 }
else if (uint64_t(ptr) % 32) {
38 fprintf(stderr,
"Pointer misalignment error: %s %s %d\n", msg, file, line);
43 static inline void gpuAssert(cudaError_t,
const char*,
int,
bool =
true){}
44 static inline void ptrAssert(
void*,
const char*,
const char*,
int,
bool =
true){}
49#define cudaCheck(ans) \
51 gpuAssert((ans), __FILE__, __LINE__); \
54#define checkPtr(ptr, msg) \
56 ptrAssert((ptr), (msg), __FILE__, __LINE__); \
61 cudaCheck(cudaDeviceSynchronize()); \
64#define cudaCheckError() \
66 cudaCheck(cudaGetLastError()); \
93#if (CUDART_VERSION < 11020)
97 static const auto supported = [] {
99 if (cudaGetDeviceCount(&count) != cudaSuccess || count < 0) count = 0;
100 std::vector<char> s(
static_cast<size_t>(count), 0);
101 for (
int i = 0; i < count; ++i) {
103 if (cudaDeviceGetAttribute(&attr, cudaDevAttrMemoryPoolsSupported, i) == cudaSuccess)
104 s[
static_cast<size_t>(i)] =
char(attr != 0);
108 return device >= 0 &&
static_cast<size_t>(device) < supported.size() && supported[
static_cast<size_t>(device)] != 0;
112#if (CUDART_VERSION < 11020) || defined(NANOVDB_USE_SYNC_CUDA_MALLOC)
120inline cudaError_t
mallocAsync(
void** d_ptr,
size_t size, cudaStream_t){
return cudaMalloc(d_ptr, size);}
127inline cudaError_t
freeAsync(
void* d_ptr, cudaStream_t){
return cudaFree(d_ptr);}
138inline cudaError_t
mallocAsync(
void** d_ptr,
size_t size, cudaStream_t stream)
141 const cudaError_t err = cudaGetDevice(&device);
142 if (err != cudaSuccess)
return err;
145 "NanoVDB: device %d does not support stream-ordered CUDA memory pools required by "
146 "cudaMallocAsync. Define NANOVDB_USE_SYNC_CUDA_MALLOC when building to allocate "
147 "synchronously with cudaMalloc/cudaFree instead.\n",
149 return cudaErrorNotSupported;
151 return cudaMallocAsync(d_ptr, size, stream);
160inline cudaError_t
freeAsync(
void* d_ptr, cudaStream_t stream)
163 const cudaError_t err = cudaGetDevice(&device);
164 if (err != cudaSuccess)
return err;
166 return cudaFreeAsync(d_ptr, stream);
175 cudaPointerAttributes ptrAtt;
176 cudaCheck(cudaPointerGetAttributes(&ptrAtt, ptr));
177 return ptrAtt.device;
183 int current = cudaInvalidDeviceId;
185 assert(current != cudaInvalidDeviceId);
201inline void printDevInfo(
int device,
const char *preMsg =
nullptr, std::FILE* file = stderr)
204 cudaGetDeviceProperties(&prop, device);
205 if (preMsg) fprintf(file,
"%s ", preMsg);
206 fprintf(file,
"GPU #%d, named \"%s\", compute capability %d.%d, %zu GB of VRAM\n",
207 device, prop.name, prop.major, prop.minor, prop.totalGlobalMem >> 30);
217 cudaStream_t mStream;
219 unique_ptr(
size_t count = 0, cudaStream_t stream = 0) : mPtr(nullptr), mStream(stream)
226 other.mPtr =
nullptr;
236 mStream = rhs.mStream;
246 T*
get()
const {
return mPtr;}
247 explicit operator bool()
const {
return mPtr !=
nullptr;}
257 NANOVDB_ASSERT(numItems > 0 && threadsPerBlock >= 32 && threadsPerBlock % 32 == 0);
258 return (numItems + threadsPerBlock - 1) / threadsPerBlock;
264#if (CUDART_VERSION < 13000)
266inline cudaError_t
memAdvise(
const void* devPtr,
size_t count, cudaMemoryAdvise advice,
int device) {
267 return cudaMemAdvise(devPtr, count, advice, device);
271inline cudaError_t
memPrefetchAsync(
const void* devPtr,
size_t count,
int dstDevice, cudaStream_t stream) {
272 return cudaMemPrefetchAsync(devPtr, count, dstDevice, stream);
278inline cudaMemLocation deviceToLocation(
int device) {
279 if (device < cudaCpuDeviceId) {
280 return {cudaMemLocationTypeInvalid, device};
281 }
else if (device == cudaCpuDeviceId) {
282 return {cudaMemLocationTypeHost, device};
284 return {cudaMemLocationTypeDevice, device};
289inline cudaError_t
memAdvise(
const void* devPtr,
size_t count, cudaMemoryAdvise advice,
int device) {
290 return cudaMemAdvise(devPtr, count, advice, deviceToLocation(device));
294inline cudaError_t
memPrefetchAsync(
const void* devPtr,
size_t count,
int dstDevice, cudaStream_t stream) {
295 return cudaMemPrefetchAsync(devPtr, count, deviceToLocation(dstDevice), 0u, stream);
299#if defined(__CUDACC__)
303template<
typename Func,
typename... Args>
304__global__ void lambdaKernel(
const size_t numItems, Func func, Args... args)
306 const int tid = blockIdx.x * blockDim.x + threadIdx.x;
307 if (tid >= numItems)
return;
314template<
typename Func,
typename... Args>
315__global__ void offsetLambdaKernel(
size_t numItems,
unsigned int offset, Func func, Args... args)
317 const unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
318 if (tid >= numItems)
return;
319 func(tid + offset, args...);
323template<
class Operator,
typename... Args>
325__launch_bounds__(Operator::MaxThreadsPerBlock, Operator::MinBlocksPerMultiprocessor)
336template<
class Operator,
typename... Args>
338__launch_bounds__(Operator::MaxThreadsPerBlock, Operator::MinBlocksPerMultiprocessor)
339void operatorKernelInstance(Operator op, Args... args)
345template<
class Operator,
typename... Args>
347__launch_bounds__(Operator::MaxThreadsPerBlock, Operator::MinBlocksPerMultiprocessor)
348void operatorKernelDynamic(Args... args)
350 extern __shared__
char smem_buf[];
352 op( args..., smem_buf );
375template<
class Operator,
typename... Args>
376void dynamicSharedMemoryLauncher(
const size_t numItems,
const size_t smem_size, cudaStream_t stream, Args... args)
378 cudaCheck(cudaFuncSetAttribute(operatorKernelDynamic<Operator, Args...>,
379 cudaFuncAttributeMaxDynamicSharedMemorySize,smem_size));
380 operatorKernelDynamic<Operator>
381 <<<numItems, Operator::MaxThreadsPerBlock, smem_size, stream>>>( args ... );
390#if defined(__CUDACC__)
391template<
typename Func,
typename... Args>
392[[deprecated(
"Use nanovdb::cuda::lambdaKernel instead")]]
393__global__ void cudaLambdaKernel(
const size_t numItems, Func func, Args... args)
395 const int tid = blockIdx.x * blockDim.x + threadIdx.x;
396 if (tid >= numItems)
return;
unique_ptr(unique_ptr &&other)
Definition Util.h:224
~unique_ptr()
Definition Util.h:228
unique_ptr & operator=(const unique_ptr &)=delete
unique_ptr(size_t count=0, cudaStream_t stream=0)
Definition Util.h:219
unique_ptr(const unique_ptr &)=delete
unique_ptr & operator=(unique_ptr &&rhs) noexcept
Definition Util.h:233
void reset()
Definition Util.h:240
T * get() const
Definition Util.h:246
int deviceCount()
Returns the number of devices with compute capability greater or equal to 1.0 that are available for ...
Definition Util.h:190
int currentDevice()
Returns the ID of the current device.
Definition Util.h:181
void printDevInfo(int device, const char *preMsg=nullptr, std::FILE *file=stderr)
Print information about a specific device.
Definition Util.h:201
int ptrToDevice(void *ptr)
Returns the device ID associated with the specified pointer.
Definition Util.h:173
bool memoryPoolsSupported(int device)
Returns true if device supports stream-ordered memory pools, i.e. cudaMallocAsync/cudaFreeAsync....
Definition Util.h:91
cudaError_t freeAsync(void *d_ptr, cudaStream_t)
Wrapper forced to synchronous cudaFree; see the mode comment above. The trailing stream argument is a...
Definition Util.h:127
cudaError_t mallocAsync(void **d_ptr, size_t size, cudaStream_t)
Wrapper forced to synchronous cudaMalloc; see the mode comment above. The trailing stream argument is...
Definition Util.h:120
size_t blocksPerGrid(size_t numItems, size_t threadsPerBlock)
Computes the number of blocks per grid given the problem size and number of threads per block.
Definition Util.h:255
cudaError_t memPrefetchAsync(const void *devPtr, size_t count, int dstDevice, cudaStream_t stream)
Compatbility wrapper for cudaMemPrefetchAsync/cudaMemPrefetchAsync.
Definition Util.h:271
cudaError_t memAdvise(const void *devPtr, size_t count, cudaMemoryAdvise advice, int device)
Compatbility wrapper for cudaMemAdvise/cudaMemAdvise.
Definition Util.h:266
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:31
#define NANOVDB_ASSERT(x)
Definition Util.h:53
#define __global__
Definition Util.h:79
static void ptrAssert(const void *ptr, const char *msg, const char *file, int line, bool abort=true)
Definition Util.h:32
static void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
Definition Util.h:24
#define cudaCheck(ans)
Definition Util.h:49