首页 > 解决方案 > cudaMemset 是否应该在从 cudaHostRegister 映射的设备指针上工作

问题描述

我从我的一位同事那里看到了示例代码,其中 cudaMemset 在 V100 上运行时似乎无法正常工作。

#include <iostream>
#include <stdio.h>
#define CUDACHECK(cmd) \
{\
    cudaError_t error  = cmd;\
    if (error != cudaSuccess) { \
        fprintf(stderr, "info: '%s'(%d) at %s:%d\n", cudaGetErrorString(error), error,__FILE__, __LINE__);\
          }\
}

__global__ void setValue(int value, int* A_d) {
     int tx = threadIdx.x + blockIdx.x * blockDim.x;
     if(tx == 0){
         A_d[tx] =  A_d[tx] + value;
     }
}

__global__ void printValue(int* A_d) {
     int tx = threadIdx.x + blockIdx.x * blockDim.x;
     if(tx == 0){
         printf("A_d: %d\n", A_d[tx]);
     }
}

int main(int argc, char* argv[ ]){
        int *A_h, *A_d;
        int size = sizeof(int);
        A_h = (int*)malloc(size);
        A_h[0] = 1;
        CUDACHECK(cudaSetDevice(0));
        CUDACHECK(cudaHostRegister(A_h, size, 0));
        CUDACHECK(cudaHostGetDevicePointer((void**)&A_d, A_h, 0));
        setValue<<<64,1,0,0>>>(5, A_d);
        cudaDeviceSynchronize();
        printf("A_h: %d\n", A_h[0]);
        A_h[0] = 100;
        printf("A_h: %d\n",A_h[0]);
        printValue<<<64,1,0,0>>>(A_d);
        cudaDeviceSynchronize();
        CUDACHECK (cudaMemset(A_d, 1, size) );
        printf("A_h: %d\n",A_h[0]);
        printValue<<<64,1,0,0>>>(A_d);
        cudaDeviceSynchronize();
        cudaHostUnregister(A_h);
        free(A_h);
}

编译并运行此示例时,输出如下所示。

/usr/local/cuda-11.0/bin/nvcc memsettest.cu -o test
./test
A_h: 6
A_h: 100
A_d: 100
A_h: 16843009
A_d: 16843009

我们期望 A_h 和 A_d 使用 cudaMemset 设置为 1。但正如所见,它被设置为一些巨大的价值。因此,cudaMemset 是否有望在 cudaHostGetDevicePointer 返回的设备指针 A_d 上工作。这个 A_d 是否预计仅在内核中使用。我们还看到 cudaMemcpy DtoH 或 HtoD 似乎在同一个设备指针 A_d 上工作。有人可以帮助我们正确的行为。

标签: cudamapped-memory

解决方案


我们期望 A_h 和 A_d 使用 cudaMemset 设置为 1。

你对如何cudaMemset工作感到困惑。从概念上讲,它与 C 标准库中的非常相似memset。您应该尝试使用相同的测试用例memset,看看它做了什么。

无论如何,cudaMemset需要一个指针、一个字节值和一个以字节为单位的大小来设置,就像memset.

所以你的cudaMemset命令:

    CUDACHECK (cudaMemset(A_d, 1, size) );

每个字节设置为 1。因为size是 4,这意味着您设置A_d[0]0x01010101(十六进制)。如果将该值插入 Windows 程序员计算器,则该值是十进制的 16843009。所以一切都按预期工作,在这里,从我所看到的。

同样,我很确定memset对于相同的测试用例/用法,您会看到相同的行为。


推荐阅读