Memory management 在CUDA中初始化设备阵列

Memory management 在CUDA中初始化设备阵列,memory-management,cuda,Memory Management,Cuda,如何初始化使用cudamaloc()分配的设备阵列 我尝试了cudaMemset,但除了0之外,它无法初始化所有值。code,因为cudaMemset如下所示,其中值初始化为5 cudaMemset(devPtr,value,number_bytes) 正如您所发现的,cudaMemset的工作原理类似于C标准库memset。引用文件: cudaError_t cudaMemset ( void * devPtr, int

如何初始化使用
cudamaloc()
分配的设备阵列

我尝试了
cudaMemset
,但除了
0之外,它无法初始化所有值。code
,因为cudaMemset如下所示,其中值初始化为5

cudaMemset(devPtr,value,number_bytes)

正如您所发现的,
cudaMemset
的工作原理类似于C标准库
memset
。引用文件:

cudaError_t cudaMemset  (   void *      devPtr,
                            int         value,
                            size_t      count    
                        )           
填充devPtr指向的内存区域的第一个计数字节 使用常量字节值

所以
value
是一个字节值。如果您执行以下操作:

int *devPtr;
cudaMalloc((void **)&devPtr,number_bytes);
const int value = 5;
cudaMemset(devPtr,value,number_bytes);
您要做的是将
devPtr
的每个字节设置为5。如果
devPtr
是一个整数数组,则结果是每个整数字的值为84215045。这可能不是你想的

使用运行时API,您可以编写自己的通用内核来实现这一点。它可以简单到

template<typename T>
__global__ void initKernel(T * devPtr, const T val, const size_t nwords)
{
    int tidx = threadIdx.x + blockDim.x * blockIdx.x;
    int stride = blockDim.x * gridDim.x;

    for(; tidx < nwords; tidx += stride)
        devPtr[tidx] = val;
}
模板
__全局无效初始化内核(T*devPtr,const T val,const size\u T nwords)
{
int tidx=threadIdx.x+blockDim.x*blockIdx.x;
int stride=blockDim.x*gridDim.x;
对于(;tidx
(标准免责声明:在浏览器中编写,从未编译,从未测试,使用风险自负)

只需实例化所需类型的模板,并使用合适的网格和块大小调用它,注意最后一个参数现在是单词计数,而不是像
cudaMemset
中那样的字节计数。无论如何,这与
cudaMemset
所做的没有什么不同,使用该API调用会导致内核启动,这与我上面发布的内容有很大不同


或者,如果您可以使用驱动程序API,则有
cuMemsetD16
cuMemsetD32
,它们的作用相同,但适用于半位和全位32位字类型。如果您需要设置64位或更大的类型(例如双精度或向量类型),您最好的选择是使用您自己的内核。

我也需要解决这个问题,但我并不真正理解其他建议的解决方案。特别是,我不明白为什么它会遍历(;tidx的网格块
,对于这个问题,内核调用以及为什么使用反直觉的字长

因此,我创建了一个更简单的单片通用内核,并对其进行了快速定制,即您可以使用它以多种方式初始化矩阵,例如将行或列设置为任意值:

template <typename T>
__global__ void kernelInitializeArray(T* __restrict__ a, const T value, 
   const size_t n, const size_t incx) {
      int tid = threadIdx.x + blockDim.x * blockIdx.x;
      if (tid*incx < n) {
           a[tid*incx] = value;
       }
}
模板
__全局无效内核初始化数组,
常数大小(n,常数大小(incx){
int tid=threadIdx.x+blockDim.x*blockIdx.x;
如果(tid*incx
然后您可以像这样调用内核:

template <typename T>
void deviceInitializeArray(T* a, const T value, const size_t n, const size_t incx) {
      int number_of_blocks = ((n / incx) + BLOCK_SIZE - 1) / BLOCK_SIZE;
      dim3 gridDim(number_of_blocks, 1);
      dim3 blockDim(BLOCK_SIZE, 1);
      kernelInitializeArray<T> <<<gridDim, blockDim>>>(a, value, n, incx);
}
模板
无效设备初始化array(T*a、常数T值、常数大小n、常数大小incx){
块的整数=((n/incx)+块大小-1)/块大小;
dim3 gridDim(块的数量,1);
dim3块DIM(块大小,1);
kernelInitializeArray(a,value,n,incx);
}

你能在你调用的
cudaMemset
中提供你的代码吗?你知道
cudaMemset
中的值是一个字节值,而不是一个字值,即目前与C标准库
memset
中的值相同,在我的代码中,我也在做同样的事情,但我只想使用cudaMemset。@user997704:没有使用
cudaMemset
的方法。运行您自己的内核,或者从驱动程序API中使用
cuMemsetD32
/
cuMemsetD32
,这对于自包含来说是很好的。调用这样的内核应该有一个合理的网格和块大小,例如,如果我的数组是N=2333,我该如何调用这个内核?我实际上不太理解stride循环。为什么你需要一个循环呢?难道每个线程不应该设置一个元素并使用它吗?@GiovanniAzua我相信这一步就是让一个线程初始化数组中的多个元素。有时候,给一个线程更多的工作比启动很多线程要好。如果你想了解为什么循环是个好主意,请看一看。