关于CudaMemset()函数

代码如下:

#define Nx 24
#define Ny 24
int main()
{        
   float *data_GPU,*test;
   cudaMalloc((void**)&data_GPU,sizeof(float)*Nx*Ny);cudaMemset(data_GPU,3.0,Nx*Ny*sizeof(float));
   cudaMalloc((void**)&test,sizeof(float)*Nx*Ny);cudaMemset(test,0.0,Nx*Ny*sizeof(float));
   dim3 threadsPerblock=(8,8);
   dim3 blockspergrid=(3,3);
   //mykernel<<<blockspergrid,threadsPerblock>>>(data_GPU,test);
   cudaDeviceSynchronize();
   printf("cudaGetLastError=%s\n",cudaGetErrorString(cudaGetLastError()));

   float *CPU_data;
   cudaMallocHost((void**)&CPU_data,sizeof(float)*Nx*Ny);
   cudaMemcpy(CPU_data,data_GPU,sizeof(float)*Nx*Ny,cudaMemcpyDeviceToHost);

   for(int iy=0;iy<Ny;iy++){
   for(int ix=0;ix<Nx;ix++){
   printf("CPU_DATA=%f\n",CPU_data[iy*Nx+ix]);
   }
   }

   cudaFreeHost(CPU_data);
   cudaFree(data_GPU);
   cudaFree(test);

   return 0;
}

kerne函数已经被屏蔽,本意是想用memset对显存上数据data_GPU初始化为3.0,但是发现好像没有成功呢?因为拷贝到CPU上发现都是0.000。
多谢斑竹

楼主您好,3.0f不可以用cudaMemset设置。

3.0f的16进制表示是:0x40400000
字节表示是:00 00 40 40 (x86 / GPU)

只有4个字节完全一样的float才能用cudaMemset清零的(例如0.0f)

建议的解决方案:
请您手写一个单独的kernel用来设置初始值为3.0f,在启动您的需要使用初始化过的缓冲区前调用此kernel,然后再调用您需要的kernel。

感谢您的周末来访。

哦哦 原来是这样啊 多谢横扫版主

您客气了,服务您是我们的荣幸。

感谢您的周末来访。

__global__ void Initialization(float *aa)
{
   int ix=blockDim.x*blockIdx.x+threadIdx.x;
   int iy=blockDim.y*blockIdx.y+threadIdx.y;
   int in_idx=iy*Nx+ix;
   aa[in_idx]=3.0;
   //__syncthreads();
}

横扫斑竹,加入这段代码有没有设备上的数据初始化为3.0的功能呢?
为什么只有数据的前24个元素是3.0,其余还是0呢

楼主您好,

您的kernel将对从0到in_idx最大值的所有aa[in_idx]元素进行设置为3.0f的操作。

这个kernel是否正确执行只取决与您的in_idx能达到的范围,也就是您的启动形状配置。

如果您真实的给出了您的代码(如上文),则您的唯一问题在与您的线程形状覆盖,请您重新设置您的启动形状配置。这是唯一您可能出错的方面。

请您立刻按照上文修改。
感谢您的周末来访。

感谢斑竹,已找到错误

[

请问横扫版主,“只有4个字节完全一样的float才能用cudaMemset清零的(例如0.0f)”,这句话是什么意思…
4个字节完全一样才能使用cudaMemset?这个为什么是这样的,或者是由哪方面的因素决定了,必须要求4字节一样的…谢谢

yuanwcj您好:

因为cudaMemset()在进行memset的时候是按照BYTE写入的,所有的字节都写成一样的内容,而且跟这段缓冲区原本存放的类型是float还是int还是其他类型无关。

所以,严格说,只有4个字节完全一样的float才能使用cudaMemset()进行初始化,而这种float一般只有0.0f比较常见,其他情况都是专门凑出来的,换句话说,cudaMemset()一般只拿来清零。

如果您需要统一初始化为其他特定的数值,请启动一个kernel对缓冲区赋值即可。

大致如此,祝您好运~

谢谢ice版主,
在C/C++中,Memset指令赋值时好像是没这个限制的;
包括从C/C++中引申出来的其他几个cudaMem*指令,同C/C++中的指令也基本上差不多,怎么到了cudaMemset指令,就有区别了呢,这个是由什么原因引起的,还是说与gpu的结构或处理方式相关,谢谢?

yuanwcj您好:

您确定C语言中string.h提供的memset()不是按每个字节操作的么?

欢迎莅临cudazone,祝您好运~

谢谢ice版主,刚查了下资料,现在才知道以前对memset函数一直有一个误解

呵呵,仔细看看函数说明吧。:lol

不客气的,欢迎您常来论坛~

祝您好运~