C++ 什么';这是';右';为CUDA实现32位memset的方法?

C++ 什么';这是';右';为CUDA实现32位memset的方法?,c++,cuda,memset,C++,Cuda,Memset,CUDA有API调用 cudaError_t cudaMemset (void *devPtr, int value, size_t count) 它使用单字节值填充缓冲区。我想用多字节值填充它。为了简单起见,假设我想用32位(4字节)的值填充devPtr,并且假设我们可以忽略endianness。现在,CUDA驱动程序具有以下API调用: CUresult cuMemsetD32(CUdeviceptr dstDevice, unsigned int ui, size_t N) 那么,仅从

CUDA有API调用

cudaError_t cudaMemset (void *devPtr, int value, size_t count)
它使用单字节值填充缓冲区。我想用多字节值填充它。为了简单起见,假设我想用32位(4字节)的值填充
devPtr
,并且假设我们可以忽略endianness。现在,CUDA驱动程序具有以下API调用:

CUresult cuMemsetD32(CUdeviceptr dstDevice, unsigned int ui, size_t N)

那么,仅从设备内存空间指针获取
CUdeviceptr
,然后进行驱动程序API调用就足够了吗?或者我还需要做些什么?

关于CUDA 3.0,运行时API设备指针(以及其他所有东西)可以与驱动程序API进行互操作。因此,可以使用
cuMemsetD32
使用32位值填充运行时API分配。
CUdeviceptr
的大小将与您平台上的
void*
的大小相匹配,可以安全地将指针从CUDA API投射到
CUdeviceptr
,反之亦然。

基于此,似乎一种合理(尽管丑陋)的方法是:

#include <stdint.h>
inline cudaError_t cudaMemsetTyped<T>(void *devPtr, T value, size_t count);

#define INSTANTIATE_CUDA_MEMSET_TYPED(_nbits) \
inline cudaError_t cudaMemsetTyped<int ## _nbits ## _t>(void *devPtr, int ## _nbits ## _t value, size_t count) { \
    cuMemsetD ## _nbits( reinterpret_cast<CUdeviceptr>(devPtr), value, count); \
} \
inline cudaError_t cudaMemsetTyped<uint ## _nbits ## _t>(void *devPtr, uint ## _nbits ## _t value, size_t count) { \
    cuMemsetD ## _nbits( reinterpret_cast<CUdeviceptr>(devPtr), reinterpret_cast<uint ## _nbits ## _t>(value), count); \
} \

INSTANTIATE_CUDA_MEMSET_TYPED(8)
INSTANTIATE_CUDA_MEMSET_TYPED(16)
INSTANTIATE_CUD_AMEMSET_TYPED(32)

#undef INSTANTIATE_CUDA_MEMSET_TYPED(_nbits)

inline cudaError_t cudaMemsetTyped<float>(void *devPtr, float value, size_t count) {
    cuMemsetD32( reinterpret_cast<CUdeviceptr>(devPtr), reinterpret_cast<int>(value), count);
}
#包括
内联cudaError\u t cudaMemsetTyped(无效*devPtr,t值,大小\u t计数);
#定义实例化\u CUDA\u MEMSET\u类型(\u nbits)\
内联cudaError_t CUDAMEMSETYPED(void*devPtr,int######t值,大小_t计数){\
cuMemsetD###nbits(重新解释转换(devPtr)、值、计数)\
} \
内联cudaError\u t CUDAMEMSETYPED(无效*devPtr,uint#######t值,大小#t计数){\
cuMemsetD####nbits(重新解释转换(devPtr)、重新解释转换(值)、计数)\
} \
实例化_CUDA_MEMSET_类型(8)
实例化_CUDA_MEMSET_类型(16)
实例化_CUD_AMEMSET_TYPED(32)
#未定义实例化\u CUDA\u MEMSET\u类型化(\u nbits)
内联cudaError\u t cudaMemsetTyped(void*devPtr、浮点值、大小\u t计数){
cuMemsetD32(重新解释强制转换(devPtr)、重新解释强制转换(值)、计数);
}

(似乎没有
cuMemset64
,所以也没有
double

但是
CUdeviceptr
是一个无符号整数,不是吗?我可以将其强制转换为一个
void*
?是的,在32位操作系统上,CUdeviceptr是一个无符号int(在64位系统上是无符号long-long),但您可以将其强制转换为void*或任何类型的数组。@einpoklum:请参阅我的编辑。您可以阅读更多内容(并看到我接受了一位CUDA原始开发人员的培训)。即使阅读了这里的讨论和博客文章,我也不清楚unsigned int(32位)的演员阵容如何能够在最新的NVidia GPU上工作,该GPU具有高达10GB的板载内存。老实说,您可能会发现,如果您想执行64位或更大的类型或通用模板解决方案,那么这样做更容易、更高效。是的,对于64位值,我想我需要一个内核(除非硬件支持跨写)。但是对于高达32位的内存,驱动程序调用应该要快得多。驱动程序调用只是启动一个内核,在某些情况下,使用定制的memset内核,它当然可以超越cudaMemset。你可能想试试基准测试,看看。@Talonmes:你肯定是在开玩笑。。。你是说我不能关掉一些DRAM的电源然后把它归零?我必须在任何地方写0?我觉得这有点难以置信。我不知道你在问什么。我的观点是,device memset和device to device memcpy作为内核在GPU上实现,并且,根据您的用例和数据类型,可以编写自定义代码,这些代码的性能与驱动程序启动的通用代码一样好,甚至更好。