cudaMemset 是否应该在从 cudaHostRegister 映射的设备指针上工作
Should cudaMemset work on the device pointer mapped from 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 上工作。
谁能帮我们纠正一下。
We expect A_h and A_d to be set to 1 with cudaMemset.
您对 cudaMemset
的工作原理感到困惑。从概念上讲,它与 C 标准库中的 memset
非常相似。您应该使用 memset
尝试相同的测试用例,看看它做了什么。
无论如何,cudaMemset
需要一个指针,一个byte值,和一个in bytes的大小来设置,就像memset
.
所以你的 cudaMemset
命令:
CUDACHECK (cudaMemset(A_d, 1, size) );
将 每个字节 设置为 1。由于 size
是 4,这意味着您将 A_d[0]
设置为 0x01010101
(在十六进制)。如果将该值插入 windows 程序员计算器,则该值为十进制的 16843009。所以一切都按预期工作,在这里,据我所见。
同样,我很确定您会在 memset
的相同测试中看到相同的行为 case/usage。
我从一位同事那里看到了示例代码,其中 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 上工作。 谁能帮我们纠正一下。
We expect A_h and A_d to be set to 1 with cudaMemset.
您对 cudaMemset
的工作原理感到困惑。从概念上讲,它与 C 标准库中的 memset
非常相似。您应该使用 memset
尝试相同的测试用例,看看它做了什么。
无论如何,cudaMemset
需要一个指针,一个byte值,和一个in bytes的大小来设置,就像memset
.
所以你的 cudaMemset
命令:
CUDACHECK (cudaMemset(A_d, 1, size) );
将 每个字节 设置为 1。由于 size
是 4,这意味着您将 A_d[0]
设置为 0x01010101
(在十六进制)。如果将该值插入 windows 程序员计算器,则该值为十进制的 16843009。所以一切都按预期工作,在这里,据我所见。
同样,我很确定您会在 memset
的相同测试中看到相同的行为 case/usage。