Arrays 将数据从设备复制到主机时出现无效参数错误

Arrays 将数据从设备复制到主机时出现无效参数错误,arrays,cuda,copy,Arrays,Cuda,Copy,将数据从设备复制回主机时遇到问题。我的数据以结构形式排列: typedef struct Array2D { double* arr; int rows; int cols; } Array2D; arr是一个“平面”阵列行和列描述了维度 下面的代码显示了我如何尝试将数据复制回主机: h_output = (Array2D*) malloc(sizeof(Array2D)); cudaMemcpy(h_output, d_ou

将数据从设备复制回主机时遇到问题。我的数据以结构形式排列:

typedef struct Array2D {
    double* arr;        
    int rows;       
    int cols;       
} Array2D;
arr
是一个“平面”阵列<代码>行和
描述了维度

下面的代码显示了我如何尝试将数据复制回主机:

h_output = (Array2D*) malloc(sizeof(Array2D));
cudaMemcpy(h_output, d_output, sizeof(Array2D), cudaMemcpyDeviceToHost);
double* h_arr = (double*) malloc(h_output->cols*h_output->rows*sizeof(double));
cudaMemcpy(h_arr, h_output->arr, h_output->cols*h_output->rows*sizeof(double), cudaMemcpyDeviceToHost);
h_output->arr = h_arr;
但是,在第四行中,执行失败,出现cuda错误11(无效参数)。我不明白为什么会这样。数组大小正确,我可以从主机访问
h_输出
h_数组
,并且都有“真实”地址

编辑 抱歉,对更多信息(=更多代码)请求的响应太晚

通过尝试访问主机上设备指针的值,我测试了指针
d_output->arr
是否是设备指针。正如所料,我没有被允许这样做,这让我想到
d_output->arr
实际上是一个有效的设备指针

该程序的目标是使用四阶龙格-库塔法求解Thiele微分方程

class CalculationSpecification
{

    /* FUNCTIONS OMITTED */

public:
    __device__ void RK4_n(CalculationSpecification* cs, CalcData data, Array2D* d_output)
    {
        double* rk4data = (double*)malloc((data.pdata->endYear - data.pdata->startYear + 1)*data.pdata->states*sizeof(double));

        /* CALCULATION STUFF HAPPENS HERE */

        // We know that rows = 51, cols = 1 and that rk4data contains 51 values as it should.
        // This was confirmed by using printf directly in this function.
        d_output->arr = rk4data;
        d_output->rows = data.pdata->endYear - data.pdata->startYear + 1;
        d_output->cols = data.pdata->states;
    }
};


class PureEndowment : CalculationSpecification
{
    /* FUNCTIONS OMITTED */

public:
    __device__ void Compute(Array2D *result, CalcData data)
    {
        RK4_n(this, data, result);
    }
};


__global__ void kernel2(Array2D *d_output)
{
    /* Other code that initializes 'cd'. */
    PureEndowment pe;
    pe.Compute(d_output,cd);
}


void prepareOutputSet(Array2D* h_output, Array2D* d_output, int count)
{
    h_output = (Array2D*) malloc(sizeof(Array2D));
    cudaMemcpy(h_output, d_output, sizeof(Array2D), cudaMemcpyDeviceToHost); // After this call I can read the correct values of row, col as well as the address of the pointer.
    double* h_arr = (double*) malloc(h_output->cols*h_output->rows*sizeof(double));
    cudaMemcpy(h_arr, h_output->arr, h_output->cols*h_output->rows*sizeof(double), cudaMemcpyDeviceToHost)
    h_output->arr = h_arr;
}

int main()
{
    Array2D *h_output, *d_output;
    cudaMalloc((void**)&d_output, sizeof(Array2D));

    kernel2<<<1,1>>>(d_output);
    cudaDeviceSynchronize();

    prepareOutputSet(h_output, d_output, 1);

    getchar();
    return 0;
}
类计算规范
{
/*省略的功能*/
公众:
__设备无效RK4(计算规格*cs、计算CDATA数据、阵列2D*d\U输出)
{
double*rk4data=(double*)malloc((data.pdata->endYear-data.pdata->startYear+1)*data.pdata->states*sizeof(double));
/*计算的东西发生在这里*/
//我们知道rows=51,cols=1,rk4data应该包含51个值。
//这是通过在此函数中直接使用printf确认的。
d_输出->arr=rk4data;
d_output->rows=data.pdata->endYear-data.pdata->startYear+1;
d_output->cols=data.pdata->states;
}
};
类别:计算规范
{
/*省略的功能*/
公众:
__设备\无效计算(Array2D*结果,CalcData数据)
{
RK4_n(此、数据、结果);
}
};
__全局无效内核2(Array2D*d_输出)
{
/*初始化“cd”的其他代码*/
纯聚乙烯;
计算(d_输出,cd);
}
无效准备输出集(Array2D*h_输出、Array2D*d_输出、整数计数)
{
h_输出=(Array2D*)malloc(sizeof(Array2D));
cudaMemcpy(h_output,d_output,sizeof(Array2D),cudaMemcpyDeviceToHost);//在这个调用之后,我可以读取行、列的正确值以及指针的地址。
double*h_arr=(double*)malloc(h_输出->cols*h_输出->行*sizeof(double));
cudaMemcpy(h_arr,h_output->arr,h_output->cols*h_output->rows*sizeof(double),cudaMemcpyDeviceToHost)
h_输出->arr=h_arr;
}
int main()
{
阵列2d*h_输出,*d_输出;
cudamaloc((void**)和d_输出,sizeof(Array2D));
内核2(d_输出);
cudaDeviceSynchronize();
准备输出(h_输出,d_输出,1);
getchar();
返回0;
}
EDIT2


此外,我现在已经测试了在设备上运行时
d_output->arr
的值与
h_output->arr
在第一次
cudaMemcpy
调用
prepareOutputSet

后的值相同,看起来
h_output
是通过调用
malloc()
分配的。在对
cudaMemcpy()
(第2行)的第一次调用中,
h_output
被用作主机指针(这似乎是正确的)。在对
cudaMemcpy()
(第4行)的第二次调用中,
h\u output->arr
被用作设备指针(这似乎不正确)。在第四行中,看起来您正在从主机内存复制到主机内存。因此,您可能只想使用一个直接的
memcpy()
,而不是
cudaMemcpy()


至少从您提供的代码来看是这样的。

您看到的错误几乎肯定是由于
h\u output->arr
不是有效的设备指针,或者是由于
h\u output->rows
h\u output->cols
的值不正确造成的。您选择不显示任何解释源内存
d_输出的内容如何设置的代码,因此无法确定问题的根本原因

为了说明这一点,下面是一个完整的、可运行的演示,展示了发布的代码:

#include <cstdlib>
#include <cstdio>

inline void GPUassert(cudaError_t code, char * file, int line, bool Abort=true)
{
    if (code != 0) {
        fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code),file,line);
        if (Abort) exit(code);
    }       
}

#define GPUerrchk(ans) { GPUassert((ans), __FILE__, __LINE__); }

typedef float Real;

typedef struct Array2D {
    Real* arr;        
    int rows;       
    int cols;       
} Array2D;

__global__ void kernel(const int m, const int n, Real *lval, Array2D *output)
{
    lval[threadIdx.x] = 1.0f + threadIdx.x;
    if (threadIdx.x == 0) {
        output->arr = lval;
        output->rows = m;
        output->cols = n;
    }
}

int main(void)
{
    const int m=8, n=8, mn=m*n;

    Array2D *d_output;
    Real *d_arr;
    GPUerrchk( cudaMalloc((void **)&d_arr,sizeof(Real)*size_t(mn)) ); 

    GPUerrchk( cudaMalloc((void **)&d_output, sizeof(Array2D)) );
    kernel<<<1,mn>>>(m,n,d_arr,d_output);
    GPUerrchk( cudaPeekAtLastError() );

    // This section of code is the same as the original question
    Array2D *h_output = (Array2D*)malloc(sizeof(Array2D));
    GPUerrchk( cudaMemcpy(h_output, d_output, sizeof(Array2D), cudaMemcpyDeviceToHost) );
    size_t sz = size_t(h_output->rows*h_output->cols)*sizeof(Real);
    Real *h_arr = (Real*)malloc(sz);
    GPUerrchk( cudaMemcpy(h_arr, h_output->arr, sz, cudaMemcpyDeviceToHost) );

    for(int i=0; i<h_output->rows; i++)
        for(int j=0; j<h_output->cols; j++)
            fprintf(stdout,"(%d %d) %f\n", i, j, h_arr[j + i*h_output->rows]);

    return 0;
}

我尝试在主机上使用cudamaloc分配指针
Array2D->arr
,而不是在设备上使用malloc分配指针。之后,代码按预期工作

这看起来很像Pavan在对问题的评论中提到的nVidia论坛线程()中描述的问题


我认为现在这个问题可能就到此为止了,因为代码运行良好。但是,如果有人建议在设备上使用malloc解决方案,请随时发布。

这(使用cudaMemcpy复制设备分配的内存)是CUDA 4.1中的已知限制。修复正在进行中,将在CUDA运行时的未来版本中发布。

最可能的错误源是
houtput->arr
不是有效的设备指针。您是否可以稍微扩展一下代码,以显示如何将
d_输出的内容分配和复制到设备?
d_输出
及其内容是使用
malloc()
在设备上分配的。我确信它包含实际数据,因为我尝试打印
d_output->arr
的内容,并获得了预期的输出。您是指
h_output
及其内容吗?因为
d_输出
不会出现在示例代码中。您无法使用cudaMemcpy从主机复制到主机!你说d_输出是用malloc分配的?你是说cuadMalloc吗?@ssnielsen你能澄清一下你是否在做Talonmes建议的事情吗?这根本不是代码所做的。它应该是非常好的,但前提是
h_output->arr
(并且扩展为
d_output->arr
,这是
$ nvcc -Xptxas="-v" -arch=sm_12 Array2D.cu 
ptxas info    : Compiling entry function '_Z6kerneliiPfP7Array2D' for 'sm_12'
ptxas info    : Used 2 registers, 16+16 bytes smem

$ cuda-memcheck ./a.out 
========= CUDA-MEMCHECK
(0 0) 1.000000
(0 1) 2.000000
(0 2) 3.000000
(0 3) 4.000000
(0 4) 5.000000
(0 5) 6.000000
(0 6) 7.000000
(0 7) 8.000000
(1 0) 9.000000
(1 1) 10.000000
(1 2) 11.000000
(1 3) 12.000000
(1 4) 13.000000
(1 5) 14.000000
(1 6) 15.000000
(1 7) 16.000000
(2 0) 17.000000
(2 1) 18.000000
(2 2) 19.000000
(2 3) 20.000000
(2 4) 21.000000
(2 5) 22.000000
(2 6) 23.000000
(2 7) 24.000000
(3 0) 25.000000
(3 1) 26.000000
(3 2) 27.000000
(3 3) 28.000000
(3 4) 29.000000
(3 5) 30.000000
(3 6) 31.000000
(3 7) 32.000000
(4 0) 33.000000
(4 1) 34.000000
(4 2) 35.000000
(4 3) 36.000000
(4 4) 37.000000
(4 5) 38.000000
(4 6) 39.000000
(4 7) 40.000000
(5 0) 41.000000
(5 1) 42.000000
(5 2) 43.000000
(5 3) 44.000000
(5 4) 45.000000
(5 5) 46.000000
(5 6) 47.000000
(5 7) 48.000000
(6 0) 49.000000
(6 1) 50.000000
(6 2) 51.000000
(6 3) 52.000000
(6 4) 53.000000
(6 5) 54.000000
(6 6) 55.000000
(6 7) 56.000000
(7 0) 57.000000
(7 1) 58.000000
(7 2) 59.000000
(7 3) 60.000000
(7 4) 61.000000
(7 5) 62.000000
(7 6) 63.000000
(7 7) 64.000000
========= ERROR SUMMARY: 0 errors