CUDA⼊门——cudaMalloc函数的理解
关于CUDA中cudaMalloc函数的参数问题
很多⼩伙伴在学习CUDA时接触到的第⼀个API:cudaMalloc会有疑问,第⼀个参数为地址指针。关于这个地址指针,今天通过这篇⽂章阐述我的理解。
cudaMalloc的原型为: cudaError_t cudaMalloc(void** devPtr, size_t size)
这个API与C语⾔中的malloc⼤同⼩异。malloc⽤法为:
int *a = (int )malloc(n sizeof(int)),返回的是⼀个int型指针,指向⼤⼩为n个int型数据的连续内存地址的⾸地址,可以理解为a是这个数组的⾸地址。
理解了这个有利于理解cudaMalloc的参数。我们在进⾏cuda编程时,第⼀步需要在GPU内分配内存,与数组的声明步骤是⼀样的。
假如我们要在GPU内申明⼀段n个⼤⼩的float型数组,我们需要定义float *addr,⽤于指向GPU内这个地址的⾸地址。因此,addr这个变量中存的就是⽤户在GPU中声明的float型数组的⾸地址。
我们需要通过cudaMalloc来改变addr中存的内容,准确地出GPU中这个数组的⾸地址。正确的调⽤⽅法为:
cudaMalloc(float(**)&addr,n*sizeof(float))
下⾯对它进⾏完整的解释:
第⼆个参数⼤家都知道具体意思了。第⼀个参数我们⾸先看到的是&addr。前⾯我们假设addr内部存放的是⼀个指向GPU中的数组的⾸地址,需要对addr的内容进⾏改变,因此我们必须采⽤引⽤的⽅式进⾏形参传递。否则,完成了cudaMalloc函数调⽤后仅仅是形参的值发⽣变化(参考C语⾔学习中的引⽤调⽤),原来我们声明的float *addr这个实参没有发⽣任何变化。注意:我们需要的是把addr指针的内容改变,⽽函数原型的devPtr返回的是地址的值,因此需要通过对addr这个指针进⾏引⽤调⽤,改变其内部的值。
理解了上⾯的内容,接着是强制类型转换成指针型指针的理解,就简单多了。前⾯说过,addr是指向地址的指针。cudaMalloc完成了
*addr的内容的改变后,需要转换数据类型。把它转换成指针型指针是对于主机端⽽⾔的(GPU称为设备端),addr这个变量是指向我们在GPU内部声明的连续地址的⾸地址,因此,我们对addr进⾏第⼀
次引⽤计算,得到的是⾸地址的值。我们需要通过这个值来在GPU的内存进⾏操作,因此需要再做⼀次引⽤计算,得到的就是GPU中连续地址的第⼀个单元,接下来就可以进⾏主机端设备端的内存内容拷贝了。
之所以这样设计,是因为在cudaMemcpy内存拷贝函数中,采⽤的形参均是地址。这个函数的原型为:
cudaError_t cudaMemcpy(void*dist,const void* src,size_t count,CudaMemcpyKind kind)
前两个参数分别是⽬的地址和源地址。完成了内存声明后,我们把addr作为形参,这时,dist指针指向了addr的地址。对dist做引⽤运算后,返回的就是我们声明好的GPU内存的⾸地址了。
总结:
cudaMalloc的参数与我们设置的地址类型数据有⼀定的关系。由于cudaMemcpy等重要的内存操作函数均以指针作为形参,因此我们需要定义⼀个与之相同类型的指针完成形参赋值。
由于指针是指向地址的,必须把我们声明的指针变量初始化为GPU的内存⾸地址。这样⼀来,addr实质上就变成了⼀个存放了地址的指针。
这也决定了cudaMalloc函数调⽤时,需要对addr进⾏引⽤计算,将GPU内存⾸地址放在addr指向的地址中。完成了这个函数调⽤molloc函数
后,addr就变成了⼀个指向GPU内存⾸地址的地址(指针)了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论