关于cudaMalloc内存分配以及二重指针

对于一个初学者,开始学习cuda内存机制的时候会存在一些疑问。最大的疑问莫过于,为什么函数中的第一个参数是void** devptr,也就是一个二级指针呢?笔者参考了网上一些作答,虽然思路还不错,但是毕竟没有抓住要害。
CUDA 中的 cudaMalloc使用二重指针(void**)的一些理解
如何理解CUDA中的cudaMalloc()的参数
实际上,这个问题不能简单的从CPU的内存来分析,而是要分析一下显存中的内存分配。
主要测试代码如下

unsigned int* gpu_block_x;
cudaMalloc((void**)&gpu_block_x, arraySizeInBytes);
printf("The address of gpu_block_x's pointer: %p\n", &gpu_block_x); //打印二级指针的地址
printf("The address of gpu_block_x: %p\n", gpu_block_x);    //打印gpu中的地址

在刚开始,unsigned int* gpu_block_x 这个指针是个空指针,没有指向任何地址。当然,为了在GPU中做数据处理,我们希望这个指针地址储存在显存中。北桥消失以后,GPU和CPU之间通过PCI-E相连。但是二者储存的地址不同。由于指令在CPU中处理,就必须让CPU知道在gpu中的地址位置。这时,就需要一个二级指针。这个二级指针储存在内存中,即CPU的物理地址中,并且指向GPU。所以二级指针的作用相当于完成了一个从CPU到GPU的映射。
下面是测试结果
测试结果

一般来说,设备如GPU使用的是总线地址。在x86平台上,物理地址就是总线地址,这是因为它们共享相同的地址空间。这也就是为什么上述地址格式相同,但是编码相差很多为了进一步验证结论的正确性,下面是完整的代码。主要增添了内核函数以及线程网格的使用。

#include "device_atomic_functions.h"
#include "device_functions.h"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include 
#include #include const int arraySizeInBytes = 128 * sizeof(int);
const int arraySizeX = 16;
const int arraySizeY = 8;
__global__ void what_is_my_address_A(unsigned int* const block_x)
{
    const unsigned int idx = (blockIdx.x * blockDim.x) + threadIdx.x;
    const unsigned int idy = (blockIdx.y * blockDim.y) + threadIdx.y;
    const unsigned int thread_idx = ((gridDim.x * blockDim.x) * idy) + idx;
    block_x[thread_idx] = blockIdx.x;
    printf("the address now is: %p\n", &block_x[thread_idx]);
}int main()
{
    unsigned int* gpu_block_x;
    const dim3 threads(16, 4);
    const dim3 blocks(1, 2);
    cudaMalloc((void**)&gpu_block_x, arraySizeInBytes);
    printf("The address of gpu_block_x's pointer: %p\n", &gpu_block_x);
    printf("The address of gpu_block_x: %p\n", gpu_block_x);
    what_is_my_address_A <<<blocks, threads >>> (gpu_block_x);
    cudaFree(gpu_block_x);
    return 0;
    
}

验证完整结果如下这也说明布局这种网格时,cudaMalloc分配内存是连续的
关于cudaMalloc内存分配以及二重指针_第1张图片

你可能感兴趣的:(并行计算学习)