Warning, file /include/VecGeom/backend/cuda/Interface.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004 #ifndef VECGEOM_BACKEND_CUDA_INTERFACE_H_
0005 #define VECGEOM_BACKEND_CUDA_INTERFACE_H_
0006
0007 #include "VecGeom/base/Config.h"
0008 #include "VecGeom/base/Global.h"
0009 #include <driver_types.h>
0010
0011 #ifdef VECGEOM_ENABLE_CUDA
0012
0013
0014
0015 #include <cuda_runtime_api.h>
0016
0017 #include <vector>
0018 #include <unordered_map>
0019 #include <type_traits>
0020
0021 namespace vecgeom {
0022
0023 #ifdef VECCORE_CUDA
0024
0025 inline namespace cuda {
0026
0027 template <typename DataClass, typename... ArgsTypes>
0028 __global__ void ConstructOnGpu(DataClass *gpu_ptr, ArgsTypes... params)
0029 {
0030 new (gpu_ptr) DataClass(params...);
0031 }
0032
0033 template <typename DataClass, typename... ArgsTypes>
0034 __global__ void ConstructArrayOnGpu(DataClass *gpu_ptr, size_t nElements, ArgsTypes... params)
0035 {
0036
0037 unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;
0038
0039 unsigned int idx = tid;
0040 while (idx < nElements) {
0041 new (gpu_ptr + idx) DataClass(params...);
0042 idx += blockDim.x * gridDim.x;
0043 }
0044 }
0045
0046
0047
0048
0049
0050
0051
0052
0053 template <typename DataClass, typename... ArgsTypes>
0054 __global__ void ConstructManyOnGpu_kernel(size_t nElements, DataClass **gpu_ptrs, const ArgsTypes *...params)
0055 {
0056 const size_t tid = threadIdx.x + blockIdx.x * blockDim.x;
0057
0058 for (size_t idx = tid; idx < nElements; idx += blockDim.x * gridDim.x) {
0059 new (gpu_ptrs[idx]) DataClass(params[idx]...);
0060 }
0061 }
0062
0063 template <typename DataClass>
0064 __global__ void CopyBBoxesToGpu(size_t nElements, DataClass **raw_ptrs, Precision *boxes)
0065 {
0066 const size_t tid = threadIdx.x + blockIdx.x * blockDim.x;
0067
0068 for (size_t idx = tid; idx < nElements; idx += blockDim.x * gridDim.x) {
0069 raw_ptrs[idx]->SetBBox({boxes[6 * idx], boxes[6 * idx + 1], boxes[6 * idx + 2]},
0070 {boxes[6 * idx + 3], boxes[6 * idx + 4], boxes[6 * idx + 5]});
0071 }
0072 }
0073
0074 }
0075
0076 #endif
0077
0078 #ifdef VECCORE_CUDA
0079 namespace cxx {
0080 #else
0081 inline namespace cxx {
0082 #endif
0083
0084 template <typename Type>
0085 Type *AllocateOnGpu(const unsigned int size)
0086 {
0087 Type *ptr = nullptr;
0088 VECGEOM_DEVICE_API_CALL(Malloc((void **)&ptr, size));
0089 return ptr;
0090 }
0091
0092 template <typename Type>
0093 Type *AllocateOnGpu()
0094 {
0095 return AllocateOnGpu<Type>(sizeof(Type));
0096 }
0097
0098 template <typename Type>
0099 void FreeFromGpu(Type *const ptr)
0100 {
0101 VECGEOM_DEVICE_API_CALL(Free(ptr));
0102 }
0103
0104 template <typename Type>
0105 void CopyToGpu(Type const *const src, Type *const tgt, const unsigned size)
0106 {
0107 VECGEOM_DEVICE_API_CALL(Memcpy(tgt, src, size, VECGEOM_DEVICE_API_SYMBOL(MemcpyHostToDevice)));
0108 }
0109
0110 template <typename Type>
0111 void CopyToGpu(Type const *const src, Type *const tgt)
0112 {
0113 CopyToGpu<Type>(src, tgt, sizeof(Type));
0114 }
0115
0116 inline void CopyFromGpu(void const *const src, void *const tgt, const unsigned size)
0117 {
0118 VECGEOM_DEVICE_API_CALL(Memcpy(tgt, src, size, VECGEOM_DEVICE_API_SYMBOL(MemcpyDeviceToHost)));
0119 }
0120
0121 class DevicePtrBase {
0122 void *fPtr;
0123 #ifdef DEBUG_DEVICEPTR
0124 size_t fAllocatedSize;
0125 bool fIncremented;
0126 #endif
0127
0128 protected:
0129 DevicePtrBase(const DevicePtrBase &orig)
0130 : fPtr(orig.fPtr)
0131 #ifdef DEBUG_DEVICEPTR
0132 ,
0133 fAllocatedSize(0), fIncremented(false)
0134 #endif
0135 {
0136 }
0137
0138 DevicePtrBase &operator=(const DevicePtrBase &orig)
0139 {
0140 fPtr = orig.fPtr;
0141 #ifdef DEBUG_DEVICEPTR
0142 fAllocatedSize = orig.fAllocatedSize;
0143 fIncremented = orig.fIncremented;
0144 #endif
0145 return *this;
0146 }
0147
0148 void MemcpyToDevice(const void *what, unsigned long nbytes)
0149 {
0150 VECGEOM_DEVICE_API_CALL(Memcpy(fPtr, what, nbytes, VECGEOM_DEVICE_API_SYMBOL(MemcpyHostToDevice)));
0151 }
0152
0153 void MemcpyToHostAsync(void *where, unsigned long nbytes, cudaStream_t stream)
0154 {
0155 VECGEOM_DEVICE_API_CALL(MemcpyAsync(where, fPtr, nbytes, VECGEOM_DEVICE_API_SYMBOL(MemcpyDeviceToHost), stream));
0156 }
0157
0158 VECCORE_ATT_HOST_DEVICE
0159 void *GetPtr() const { return fPtr; }
0160
0161 void Free()
0162 {
0163 VECGEOM_DEVICE_API_CALL(Free((void *)fPtr));
0164 #ifdef DEBUG_DEVICEPTR
0165 fAllocatedSize = 0;
0166 #endif
0167 }
0168
0169 void Increment(long add)
0170 {
0171 fPtr = (char *)fPtr + add;
0172 #ifdef DEBUG_DEVICEPTR
0173 if (add) fIncremented = true;
0174 #endif
0175 }
0176
0177 public:
0178 DevicePtrBase()
0179 : fPtr(0)
0180 #ifdef DEBUG_DEVICEPTR
0181 ,
0182 fAllocatedSize(0), fIncremented(0)
0183 #endif
0184 {
0185 }
0186
0187 explicit DevicePtrBase(void *input)
0188 : fPtr(input)
0189 #ifdef DEBUG_DEVICEPTR
0190 ,
0191 fAllocatedSize(0), fIncremented(0)
0192 #endif
0193 {
0194 }
0195
0196 ~DevicePtrBase() { }
0197
0198 void Malloc(unsigned long size)
0199 {
0200 VECGEOM_DEVICE_API_CALL(Malloc((void **)&fPtr, size));
0201 #ifdef DEBUG_DEVICEPTR
0202 fAllocatedSize = size;
0203 #endif
0204 }
0205 };
0206
0207 template <typename T>
0208 class DevicePtr;
0209
0210 template <typename Type, typename Derived = DevicePtr<Type>>
0211 class DevicePtrImpl : public DevicePtrBase {
0212 protected:
0213 DevicePtrImpl(const DevicePtrImpl & ) = default;
0214 DevicePtrImpl &operator=(const DevicePtrImpl & ) = default;
0215 DevicePtrImpl() = default;
0216 explicit DevicePtrImpl(void *input) : DevicePtrBase(input) {}
0217 ~DevicePtrImpl() = default;
0218
0219 public:
0220 void Allocate(unsigned long nelems = 1) { Malloc(nelems * Derived::SizeOf()); }
0221
0222 void Deallocate() { Free(); }
0223
0224 void ToDevice(const Type *what, unsigned long nelems = 1) { MemcpyToDevice(what, nelems * Derived::SizeOf()); }
0225 void FromDevice(Type *where, cudaStream_t stream)
0226 {
0227
0228 MemcpyToHostAsync(where, Derived::SizeOf(), stream);
0229 }
0230 void FromDevice(Type *where, unsigned long nelems, cudaStream_t stream)
0231 {
0232
0233 MemcpyToHostAsync(where, nelems * Derived::SizeOf(), stream);
0234 }
0235
0236 VECCORE_ATT_HOST_DEVICE
0237 Type *GetPtr() const { return reinterpret_cast<Type *>(DevicePtrBase::GetPtr()); }
0238
0239 VECCORE_ATT_HOST_DEVICE
0240 operator Type *() const { return GetPtr(); }
0241
0242 Derived &operator++()
0243 {
0244 Increment(Derived::SizeOf());
0245 return *(Derived *)this;
0246 }
0247
0248 Derived operator++(int)
0249 {
0250 Derived tmp(*(Derived *)this);
0251 Increment(Derived::SizeOf());
0252 return tmp;
0253 }
0254
0255 Derived operator+(const size_t &rhs)
0256 {
0257 Derived tmp(*(Derived *)this);
0258 tmp.Increment(rhs);
0259 return tmp;
0260 }
0261
0262 Derived &operator+=(long len)
0263 {
0264 Increment(len * Derived::SizeOf());
0265 return *(Derived *)this;
0266 }
0267 };
0268
0269 template <typename Type>
0270 class DevicePtr : public DevicePtrImpl<Type> {
0271 public:
0272 DevicePtr() = default;
0273 DevicePtr(const DevicePtr &) = default;
0274 DevicePtr &operator=(const DevicePtr &orig) = default;
0275
0276
0277 explicit DevicePtr(void *input) : DevicePtrImpl<Type>(input) {}
0278
0279
0280
0281
0282
0283 template <typename inputType>
0284 explicit DevicePtr(DevicePtr<inputType> const &input) : DevicePtrImpl<Type>((void *)input)
0285 {
0286 }
0287
0288
0289 DevicePtr(DevicePtr<const Type> const &input,
0290 typename std::enable_if<!std::is_const<Type>::value, Type>::type * = nullptr) = delete;
0291
0292 #ifdef VECCORE_CUDA
0293
0294 template <typename inputType, typename std::enable_if<std::is_base_of<Type, inputType>::value>::type * = nullptr>
0295 DevicePtr(DevicePtr<inputType> const &input) : DevicePtrImpl<Type>(input.GetPtr())
0296 {
0297 }
0298
0299
0300 template <typename inputType, typename std::enable_if<std::is_base_of<Type, inputType>::value>::type * = nullptr>
0301 DevicePtr(DevicePtr<const inputType> const &input) = delete;
0302 #endif
0303
0304 #ifdef VECCORE_CUDA
0305 template <typename... ArgsTypes>
0306 void Construct(ArgsTypes... params) const
0307 {
0308 ConstructOnGpu<<<1, 1>>>(this->GetPtr(), params...);
0309 }
0310
0311 template <typename... ArgsTypes>
0312 void ConstructArray(size_t nElements, ArgsTypes... params) const
0313 {
0314 ConstructArrayOnGpu<<<nElements, 1>>>(this->GetPtr(), nElements, params...);
0315 }
0316
0317 static size_t SizeOf() { return sizeof(Type); }
0318
0319 #else
0320 template <typename... ArgsTypes>
0321 void Construct(ArgsTypes... params) const;
0322 template <typename... ArgsTypes>
0323 void ConstructArray(size_t nElements, ArgsTypes... params) const;
0324
0325 static size_t SizeOf();
0326 #endif
0327 };
0328
0329 template <typename Type>
0330 class DevicePtr<const Type> : private DevicePtrImpl<const Type> {
0331 public:
0332 DevicePtr() = default;
0333 DevicePtr(const DevicePtr &) = default;
0334 DevicePtr &operator=(const DevicePtr &orig) = default;
0335
0336
0337 explicit DevicePtr(void *input) : DevicePtrBase(input) {}
0338
0339
0340
0341
0342
0343 template <typename inputType>
0344 explicit DevicePtr(DevicePtr<inputType> const &input) : DevicePtrImpl<const Type>((void *)input)
0345 {
0346 }
0347
0348
0349 DevicePtr(DevicePtr<typename std::remove_const<Type>::type> const &input) : DevicePtrImpl<const Type>((void *)input)
0350 {
0351 }
0352
0353 #ifdef VECCORE_CUDA
0354
0355 template <typename inputType, typename std::enable_if<std::is_base_of<Type, inputType>::value>::type * = nullptr>
0356 DevicePtr(DevicePtr<inputType> const &input) : DevicePtrImpl<const Type>(input.GetPtr())
0357 {
0358 }
0359 #endif
0360
0361 VECCORE_ATT_HOST_DEVICE
0362 const Type *GetPtr() const { return reinterpret_cast<const Type *>(DevicePtrBase::GetPtr()); }
0363
0364 VECCORE_ATT_HOST_DEVICE
0365 operator const Type *() const { return GetPtr(); }
0366
0367 #ifdef VECCORE_CUDA
0368 template <typename DataClass, typename... ArgsTypes>
0369 void Construct(ArgsTypes... params) const
0370 {
0371 ConstructOnGpu<<<1, 1>>>(*(*this), params...);
0372 }
0373
0374 template <typename... ArgsTypes>
0375 void ConstructArray(size_t nElements, ArgsTypes... params) const
0376 {
0377 ConstructArrayOnGpu<<<nElements, 1>>>(this->GetPtr(), nElements, params...);
0378 }
0379
0380 static size_t SizeOf() { return sizeof(Type); }
0381
0382 #else
0383 template <typename... ArgsTypes>
0384 void Construct(ArgsTypes... params) const;
0385 template <typename... ArgsTypes>
0386 void ConstructArray(size_t nElements, ArgsTypes... params) const;
0387
0388 static size_t SizeOf();
0389 #endif
0390 };
0391
0392 namespace CudaInterfaceHelpers {
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 template <typename Arg_t, typename... Args_t>
0404 void allocateAndCopyToGpu(std::unordered_map<const void *, void *> &cpuToGpuMapping, std::size_t nElement,
0405 const Arg_t *toCopy, const Args_t *...restToCopy)
0406 {
0407 const auto nByte = sizeof(toCopy[0]) * nElement;
0408 const void *hostMem = toCopy;
0409 void *deviceMem = AllocateOnGpu<void *>(nByte);
0410 cpuToGpuMapping[hostMem] = deviceMem;
0411 CopyToGpu(hostMem, deviceMem, nByte);
0412
0413 if constexpr (sizeof...(Args_t) > 0) {
0414 allocateAndCopyToGpu(cpuToGpuMapping, nElement, restToCopy...);
0415 }
0416 }
0417
0418 }
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428 template <class DataClass, class DevPtr_t, typename... Args_t>
0429 void ConstructManyOnGpu(std::size_t nElement, const DevPtr_t *gpu_ptrs, const Args_t *...params)
0430 #ifdef VECCORE_CUDA
0431 {
0432 using namespace CudaInterfaceHelpers;
0433 std::unordered_map<const void *, void *> cpuToGpuMem;
0434 std::vector<DataClass *> raw_gpu_ptrs;
0435 std::transform(gpu_ptrs, gpu_ptrs + nElement, std::back_inserter(raw_gpu_ptrs),
0436 [](const DevPtr_t &ptr) { return static_cast<DataClass *>(ptr.GetPtr()); });
0437 allocateAndCopyToGpu(cpuToGpuMem, nElement, raw_gpu_ptrs.data(), params...);
0438
0439 ConstructManyOnGpu_kernel<<<128, 32>>>(raw_gpu_ptrs.size(),
0440 static_cast<decltype(raw_gpu_ptrs.data())>(cpuToGpuMem[raw_gpu_ptrs.data()]),
0441 static_cast<decltype(params)>(cpuToGpuMem[params])...);
0442
0443 for (const auto &memCpu_memGpu : cpuToGpuMem) {
0444 FreeFromGpu(memCpu_memGpu.second);
0445 }
0446
0447 VECGEOM_DEVICE_API_CALL(GetLastError());
0448 }
0449 #else
0450 ;
0451 #endif
0452
0453 template <class DataClass, class DevPtr_t>
0454 void CopyBBoxesToGpuImpl(std::size_t nElement, const DevPtr_t *gpu_ptrs, Precision *boxes_data)
0455 #ifdef VECCORE_CUDA
0456 {
0457 std::unordered_map<const void *, void *> cpuToGpuMem;
0458 std::vector<DataClass *> raw_gpu_ptrs;
0459 std::transform(gpu_ptrs, gpu_ptrs + nElement, std::back_inserter(raw_gpu_ptrs),
0460 [](const DevPtr_t &ptr) { return static_cast<DataClass *>(ptr.GetPtr()); });
0461
0462 const auto nByteBoxes = 6 * nElement * sizeof(Precision);
0463 const auto nByteVolumes = nElement * sizeof(DataClass *);
0464 Precision *boxes_data_gpu = AllocateOnGpu<Precision>(nByteBoxes);
0465 DataClass **raw_gpu_ptrs_gpu = AllocateOnGpu<DataClass *>(nByteVolumes);
0466
0467 CopyToGpu(boxes_data, boxes_data_gpu, nByteBoxes);
0468 CopyToGpu(raw_gpu_ptrs.data(), raw_gpu_ptrs_gpu, nByteVolumes);
0469 VECGEOM_DEVICE_API_CALL(DeviceSynchronize());
0470
0471 CopyBBoxesToGpu<DataClass><<<128, 32>>>(raw_gpu_ptrs.size(), raw_gpu_ptrs_gpu, boxes_data_gpu);
0472
0473 FreeFromGpu(boxes_data_gpu);
0474 FreeFromGpu(raw_gpu_ptrs_gpu);
0475 }
0476 #else
0477 ;
0478 #endif
0479
0480 }
0481
0482 }
0483
0484 #endif
0485
0486 #endif