分配两个调用cudaMalloc一次的数组

allocate two arrays calling cudaMalloc once

本文关键字:一次 数组 调用 两个 分配 cudaMalloc      更新时间:2023-10-16

内存分配是GPU中最耗时的操作之一,因此我想通过使用以下代码调用cudaMalloc一次来分配2个阵列:

int numElements = 50000;
size_t size = numElements * sizeof(float);
//declarations-initializations
float *d_M = NULL;
err = cudaMalloc((void **)&d_M, 2*size);
//error checking
// Allocate the device input vector A
float *d_A = d_M;

// Allocate the device input vector B
float *d_B = d_M + size;
err = cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
//error checking
err = cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);
//error checking

原始代码位于名为vectorAdd.cu的cuda工具包的samples文件夹中,因此您可以假设h_A、h_B已正确启动,并且代码在没有我所做修改的情况下正常工作
结果是,第二个cudaMemcpy返回了一个错误,消息为无效参数

操作"d_M+size"似乎不会返回人们所期望的结果,因为设备内存的行为不同,但我不知道是怎么回事。

有可能让我的方法(调用一次cudaMalloc为两个数组分配内存)发挥作用吗?欢迎就这是否是一个好方法发表任何意见/回答。

UPDATE
正如Robert和dreamcrash的回答所建议的那样,我必须向指针d_M添加元素数(numElements),而不是字节数。只是为了参考,没有明显的加速。

您只需要更换

float *d_B = d_M + size;

带有

float *d_B = d_M + numElements;

这是指针算术,如果您有一个浮点数组R = [1.0,1.2,3.3,3.4],您可以通过执行printf("%f",*R);来打印它的第一个位置。第二个位置呢?你只需要做printf("%fn",*(++R));,就可以做r[0] + 1。你没有像以前那样做r[0] + sizeof(float)。执行r[0] + sizeof(float)时,您将访问自size(float) = 4以来位于r[4]位置的元素。

当您声明float *d_B = d_M + numElements;时,编译器假设d_b将在内存中连续分配,并且每个元素的大小将为float。因此,您不需要以字节为单位指定距离,而是以元素为单位指定,编译器将为您计算。这种方法更人性化,因为用元素表示指针算术比用字节表示更直观。此外,它还更具可移植性,因为如果给定类型的字节数根据底层体系结构发生变化,编译器将为您处理。因此,一个人的代码不会因为假设了固定的字节大小而中断。


你说过"结果是,第二个cudaMemcpy返回了一个错误,其消息为无效参数">

如果您打印与此错误相对应的数字,它将打印11,如果您检查CUDA API,则验证此错误是否对应于:

cudaErrorInvalidValue

这表示传递给API的一个或多个参数调用不在可接受的值范围内。

在您的示例中,这意味着浮点*d_B = d_M + size;超出了范围。

您已经为100000浮点分配了空间,d_a将从0开始到50000,但根据您的代码,d_b将从numElements * sizeof(float);开始50000*4=200000,因为200000>100000您将得到无效参数