基本 CUDA 指针/数组内存分配和使用

Posted

技术标签:

【中文标题】基本 CUDA 指针/数组内存分配和使用【英文标题】:Basic CUDA pointer/array memory allocation and use 【发布时间】:2013-07-02 15:29:07 【问题描述】:

我上周开始使用 CUDA,因为我必须将现有的 c++ 程序转换为 cuda 以进行研究。

这是 CUDA by Example 一书中的一个基本示例,我推荐给任何想学习 CUDA 的人!

有人能解释一下如何使用空指针“dev_c”分配 GPU 内存吗?

HANDLE_ERROR( cudaMalloc( (void**)&dev_c, N * sizeof(int) ) );

那么,在调用函数'add'时不传递任何'dev_c'值,而是将*c视为全局函数中的一个数组并从函数内部写入?为什么在任何地方都没有将其定义为数组时这可能?

add<<<N,1>>>( dev_a, dev_b, dev_c );

最后,在执行以下加法时,术语 c[0]、c[1] 等到底保存在哪里?

c[tid] = a[tid] + b[tid];

我希望我能很好地解释自己,但请随时提出任何后续问题。对 C 和 CUDA 都是新手,所以要友好:D

完整代码如下:

#include "book.h"

#define N   1000

__global__ void add( int *a, int *b, int *c ) 
    int tid = blockIdx.x;    // this thread handles the data at its thread id
    if (tid < N)
        c[tid] = a[tid] + b[tid];


int main( void ) 
    int a[N], b[N], c[N];
    int *dev_a, *dev_b, *dev_c;

    // allocate the memory on the GPU
    HANDLE_ERROR( cudaMalloc( (void**)&dev_a, N * sizeof(int) ) );
    HANDLE_ERROR( cudaMalloc( (void**)&dev_b, N * sizeof(int) ) );
    HANDLE_ERROR( cudaMalloc( (void**)&dev_c, N * sizeof(int) ) );

    // fill the arrays 'a' and 'b' on the CPU
    for (int i=0; i<N; i++) 
        a[i] = -i;
        b[i] = i * i;
    

    // copy the arrays 'a' and 'b' to the GPU
    HANDLE_ERROR( cudaMemcpy( dev_a, a, N * sizeof(int),
                                cudaMemcpyHostToDevice ) );
    HANDLE_ERROR( cudaMemcpy( dev_b, b, N * sizeof(int),
                                cudaMemcpyHostToDevice ) );

    add<<<N,1>>>( dev_a, dev_b, dev_c );

    // copy the array 'c' back from the GPU to the CPU
    HANDLE_ERROR( cudaMemcpy( c, dev_c, N * sizeof(int),
                                cudaMemcpyDeviceToHost ) );

    // display the results
    for (int i=0; i<N; i++) 
        printf( "%d + %d = %d\n", a[i], b[i], c[i] );
    

    // free the memory allocated on the GPU
    HANDLE_ERROR( cudaFree( dev_a ) );
    HANDLE_ERROR( cudaFree( dev_b ) );
    HANDLE_ERROR( cudaFree( dev_c ) );

    return 0;

谢谢!

【问题讨论】:

【参考方案1】:

不可能在 SO 问题的空间中教授 CUDA。我将尝试回答您的问题,但您可能应该利用一些资源。如果您不了解 C 或 C++,这将特别困难,因为典型的 CUDA 编程依赖于这些。

您可能想参加一些介绍性网络研讨会here,例如:

使用 CUDA C 进行 GPU 计算 - 简介 (2010) 介绍使用 CUDA C 进行 GPU 计算的基础知识。概念将通过代码示例的演练进行说明。无需先前的 GPU 计算经验

使用 CUDA C 的 GPU 计算 – 高级 1 (2010) 一级优化技术,例如全局内存优化和处理器利用率。将使用真实的代码示例来说明概念

现在回答你的问题:

有人能解释一下如何使用空指针“dev_c”分配 GPU 内存吗?

dev_c 一开始是一个空指针。但是cudaMalloc 函数allocates GPU memory 根据传递给它的大小,建立一个指向该分配的指针,并将该指针存储到dev_c 指针中。它可以这样做,因为我们是 passing the address of dev_c,而不是实际的指针本身。

那么,在调用函数'add'时不传递任何'dev_c'值,而是将*c视为全局函数中的数组并从函数内部写入?为什么在任何地方都没有将其定义为数组时这可能?

在 C 中,指针(dev_c 就是这样)可以指向单个值或值数组。指针本身不包含有关它指向多少数据的信息。由于dev_c 是存储结果的,并且它已经被前面的cudaMalloc 函数正确初始化,我们可以使用它来将操作的结果存储在内核中。 dev_c 实际上指向int (一个数组)的存储区域,其大小由N * sizeof(int) 给出,传递给前面的cudaMalloc 函数。

最后,在执行以下加法时,术语 c[0]、c[1] 等到底保存在哪里?

在c中,当我们有这样的函数定义时:

void my_function(int *c)...

这表示函数中的语句可以引用名为 c 的变量,就好像它是指向一个或多个 int 值的指针(单个值或值数组,从指向的位置开始存储) c)。

当我们调用该函数时,我们可以使用一些其他变量作为 argument,函数 parameter 称为 c,如下所示:

int my_ints[32];
my_function(my_ints);

现在,在my_function 内部,无论参数 c 被引用,它将使用(指针)my_ints 给出的参数 值。

相同的概念适用于 cuda 函数(内核)及其参数和参数。

【讨论】:

谢谢,现在这更有意义了!那么这是否意味着 (array) c 中的值被保存在先前在 cudaMalloc( (void**)&dev_c, N * sizeof(int) ) 中分配的 GPU 全局内存中? 是的。 c 的内核用法存储在为c 参数传递的参数 中,在本例中为dev_c。并且dev_c 之前已在设备全局内存中设置了分配的大小。这本质上是 C 行为,几乎与 CUDA 无关。 知道了!再次感谢您的详细回复,非常感谢!

以上是关于基本 CUDA 指针/数组内存分配和使用的主要内容,如果未能解决你的问题,请参考以下文章

CUDA中统一内存的函数指针分配

在 CUDA 中混合自定义内存管理和推力

4-数组指针与字符串1.4-动态内存分配

CUDA C

CUDA统一内存

CUDA统一内存