【问题标题】:cudaMemcpy returns cudaErrorInvalidArgument when reading from Device to Host, unclear why [duplicate]从设备读取到主机时,cudaMemcpy 返回 cudaErrorInvalidArgument,不清楚原因 [重复]
【发布时间】:2017-07-12 23:44:41
【问题描述】:

第一篇文章在这里。我目前正在做一个项目,该项目需要将一个大型二维数组(大约 1,000,000x7)写入我的 GPU,进行一些计算,然后将其返回给主机。由于我想用如此大的数组快速完成,我尝试将数组展平以帮助将其相当直接地传递到 GPU。数组成功写入(或者当我写入设备时,至少 cudaMalloc 和 cudaMemcpy 都返回 cudaSuccess),但是当我尝试读取它时,cudaMemcpy 返回一个无效参数错误。

我无法弄清楚为什么会这样,因为我认为我应该在设备上写入一个有效的一维数组(展平)并将其读回,并且我认为我提供了正确的论点这个。我在网上找到的这个错误的唯一结果涉及将 dst 和 src 参数交换为 cudaMemcpy,但我想我已经找到了。

这是重现问题的我的代码的简化版本:

#include <iostream>

using namespace std;

void alloc2dArray(float ** &arr, unsigned long int rows, unsigned long int cols){ 

    arr = new float*[rows];

    arr[0] = new float[rows * cols];

    for(unsigned long int i = 1; i < rows; i++) arr[i] = arr[i - 1] + cols;
}

void write2dArrayToGPU(float ** arr, float * devPtr, unsigned long int rows, unsigned long int cols){

    if(cudaSuccess != cudaMalloc((void**)&devPtr, sizeof(float) * rows * cols)) cerr << "cudaMalloc Failed";

    if(cudaSuccess != cudaMemcpy(devPtr, arr[0], sizeof(float) * rows * cols, cudaMemcpyHostToDevice)) cerr << "cudaMemcpy Write Failed";
}

void read2dArrayFromGPU(float ** arr, float * devPtr, unsigned long int rows, unsigned long int cols){

    if(cudaSuccess != cudaMemcpy(arr[0], devPtr, sizeof(float) * rows * cols, cudaMemcpyDeviceToHost)) cerr << "cudaMemcpy Read Failed" << endl;
}

int main(){

int R = 100;
int C = 7;

cout << "Allocating an " << R << "x" << C << " array ...";
float ** arrA;
alloc2dArray(arrA, R, C);


cout << "Assigning some values ...";
for(int i = 0; i < R; i++){
    for(int j = 0; j < C; j++){
        arrA[i][j] = i*C + j;
    }
}
cout << "Done!" << endl;


cout << "Writing to the GPU ...";
float * Darr = 0;
write2dArrayToGPU(arrA, Darr, R, C);
cout << " Done!" << endl;

cout << "Allocating second " << R << "x" << C << " array ...";
float ** arrB;
alloc2dArray(arrB, R, C);
cout << "Done!" << endl;

cout << "Reading from the GPU into the new array ...";
read2dArrayFromGPU(arrB, Darr, R, C);


}

我用

在我的笔记本电脑上编译并运行它
 $nvcc -arch=sm_30 test.cu -o test
 $optirun cuda-memcheck ./test

并得到结果:

========= CUDA-MEMCHECK
Allocating an 100x7 array ...Assigning some values ...Done!
Writing to the GPU ... Done!
Allocating second 100x7 array ...Done!
========= Program hit cudaErrorInvalidValue (error 11) due to "invalid argument" on CUDA API call to cudaMemcpy. 
=========     Saved host backtrace up to driver entry point at error
Reading from the GPU into the new array ...=========     Host Frame:/usr/lib64/nvidia-bumblebee/libcuda.so.1 [0x2ef343]
cudaMemcpy Read Failed=========     Host Frame:./test [0x38c6f]
=========     Host Frame:./test [0x2f08]
=========     Host Frame:./test [0x3135]
=========     Host Frame:/usr/lib64/libc.so.6 (__libc_start_main + 0xf1) [0x20401]
=========     Host Frame:./test [0x2c6a]

=========
========= ERROR SUMMARY: 1 error

我对 CUDA 比较陌生,还在学习中,因此我们将不胜感激,谢谢!

【问题讨论】:

  • CUDA 与 C 无关。
  • 您不能将 devPtr 作为单个指针参数传递给函数,在该指针上执行 cudaMalloc,然后期望分配的指针值显示在调用环境。这是传递值的常见错误,当然还有其他类似的问题。如this one。您可能想在那里研究答案,您的问题可以说是那个问题的重复。

标签: c++ cuda


【解决方案1】:

感谢 Robert Crovella 通过上面的评论为我指明了正确的方向,并链接了类似的 question

要点是,通过将 devPtr 按值而不是指针或引用传递到我的 GPU writeread 函数中,cudaMalloc 和 cudaMemcpy 函数仅作用于函数范围内的副本。

两种解决方案 - (这两种解决方案都不会为我抛出错误)

首先:通过引用将devPtr 传递给write2dArrayToGPUread2dArrayFromGPU,然后解决方案看起来像。

#include <iostream>

using namespace std;


void alloc2dArray(float ** &arr, unsigned long int rows, unsigned long int cols){

    arr = new float*[rows];

    arr[0] = new float[rows * cols];

    for(unsigned long int i = 1; i < rows; i++) arr[i] = arr[i - 1] + cols;
}

//changed float * devPtr to float *  &devPtr
void write2dArrayToGPU(float ** arr, float * &devPtr, unsigned long int rows, unsigned long int cols){

    if(cudaSuccess != cudaMalloc((void**)&devPtr, sizeof(float) * rows * cols)) cerr << "cudaMalloc Failed";

    if(cudaSuccess != cudaMemcpy(devPtr, arr[0], sizeof(float) * rows * cols, cudaMemcpyHostToDevice)) cerr << "cudaMemcpy Write Failed";
}

//changed float * devPtr to float * &devPtr
void read2dArrayFromGPU(float ** arr, float * &devPtr, unsigned long int rows, unsigned long int cols){

    if(cudaSuccess != cudaMemcpy(arr[0], devPtr, sizeof(float) * rows * cols, cudaMemcpyDeviceToHost)) cerr << "cudaMemcpy Read Failed" << endl;
}

int main(){

int R = 100;
int C = 7;

cout << "Allocating an " << R << "x" << C << " array ...";
float ** arrA;
alloc2dArray(arrA, R, C);


cout << "Assigning some values ...";
for(int i = 0; i < R; i++){
    for(int j = 0; j < C; j++){
        arrA[i][j] = i*C + j;
    }
}
cout << "Done!" << endl;


cout << "Writing to the GPU ...";
float * Darr = 0;
write2dArrayToGPU(arrA, Darr, R, C);
cout << " Done!" << endl;

cout << "Allocating second " << R << "x" << C << " array ...";
float ** arrB;
alloc2dArray(arrB, R, C);
cout << "Done!" << endl;

cout << "Reading from the GPU into the new array ...";
read2dArrayFromGPU(arrB, Darr, R, C);


}

第二:通过指针传递devPtr,使解决方案看起来像

#include <iostream>

using namespace std;

void alloc2dArray(float ** &arr, unsigned long int rows, unsigned long int cols){

    arr = new float*[rows];

    arr[0] = new float[rows * cols];

    for(unsigned long int i = 1; i < rows; i++) arr[i] = arr[i - 1] + cols;
}

//changed float * devPtr to float ** devPtr
void write2dArrayToGPU(float ** arr, float ** devPtr, unsigned long int rows, unsigned long int cols){

    if(cudaSuccess != cudaMalloc((void**)devPtr, sizeof(float) * rows * cols)) cerr << "cudaMalloc Failed";

    if(cudaSuccess != cudaMemcpy(*devPtr, arr[0], sizeof(float) * rows * cols, cudaMemcpyHostToDevice)) cerr << "cudaMemcpy Write Failed";
}

//changed float * devPtr to float ** devPtr
void read2dArrayFromGPU(float ** arr, float ** devPtr, unsigned long int rows, unsigned long int cols){

    if(cudaSuccess != cudaMemcpy(arr[0], *devPtr, sizeof(float) * rows * cols, cudaMemcpyDeviceToHost)) cerr << "cudaMemcpy Read Failed" << endl;
}

int main(){

int R = 100;
int C = 7;

cout << "Allocating an " << R << "x" << C << " array ...";
float ** arrA;
alloc2dArray(arrA, R, C);


cout << "Assigning some values ...";
for(int i = 0; i < R; i++){
    for(int j = 0; j < C; j++){
        arrA[i][j] = i*C + j;
    }
}
cout << "Done!" << endl;


cout << "Writing to the GPU ...";
float * Darr = 0;
write2dArrayToGPU(arrA, &Darr, R, C); \\changed Darr to &Darr
cout << " Done!" << endl;

cout << "Allocating second " << R << "x" << C << " array ...";
float ** arrB;
alloc2dArray(arrB, R, C);
cout << "Done!" << endl;

cout << "Reading from the GPU into the new array ...";
read2dArrayFromGPU(arrB, &Darr, R, C); // changed Darr to &Darr


}

【讨论】:

    猜你喜欢
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 2012-02-09
    • 2011-12-19
    • 2011-08-24
    • 2021-01-25
    相关资源
    最近更新 更多