繁体   English   中英

如何将2D阵列从设备复制到Cuda中的主机?

[英]How to copy a 2D array from Device to Host in Cuda?

我想将fft操作的结果从设备复制到主机。

这就是发生的情况。 输入是一个指向浮点数的指针。 在运行时分配值。 然后将其传输到GPU并计算fft。 然后将结果传输到float2 2D数组。 但是我得到的结果是错误的。 它包含所有零。 那么我该如何克服这个问题呢?

#define NRANK 2
#define BATCH 10

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cufft.h>
#include <stdio.h> 

#include <iostream>
#include <vector>

using namespace std;


float func(int,int){
              return 2.0f;  // some value get return. I have put a dummy value here
} 
int main()
    { 

    const size_t NX = 4;
    const size_t NY = 5;

    // Input array - host side
    float **a = new float*[NX];  

    for (int r = 0; r < NX; ++r)  // this can be also done on GPU
        {
        a[r] = new float[NY];
        for (int c = 0; c < NY; ++c)
            {            
                a[r][c] = func(r,c);         
            }
        }

    // Output array - host side  
    float2 c[NX][NY] = { 0 };


    cufftHandle plan;
    cufftComplex *data;   // Input and output arrays - device side
    int n[NRANK] = {NX, NY};

    // Transfer the data from host to device - have to do it like this becase
    // the array is a dynamic array
    cudaMalloc((void**)&data, sizeof(cufftComplex)*NX*(NY/2+1));
    for(int i=0; i<NX; ++i){
        cudaMemcpy(reinterpret_cast<float*>(data) + i*NY, a[i], sizeof(float)*NY,     
             cudaMemcpyHostToDevice);
     }

    /* Create a 2D FFT plan. */
    cufftPlanMany(&plan, NRANK, n,NULL, 1, 0,NULL, 1, 0,CUFFT_C2C,BATCH);
    cufftSetCompatibilityMode(plan, CUFFT_COMPATIBILITY_NATIVE);
    cufftExecC2C(plan, data, data, CUFFT_FORWARD);
    cudaThreadSynchronize();
    cudaMemcpy(c, data, sizeof(float2)*NX*NY, cudaMemcpyDeviceToHost);

    // Print the values of c  ---- ALL ARE 0
    for (int i = 0; i < NX; i++)
        {
        for (int j =0 ; j< NY; j++)
            {
            printf(" %f + %fi ",c[i][j].x,c[i][j].y);
            b
            }
        printf("\n");
        }


    cufftDestroy(plan);
    cudaFree(data);

    return 0;
    }

我该如何解决这个问题?


编辑

考虑了Robert Crovella的建议后,我将代码修改为

// Output array - host side
float2 c[NX][NY + 2] ;

// New device side variable that will hold the result from the FFT size - twice as input {2 x NX*(NY/2 + 1)}
cufftComplex *data_out;
cudaMalloc((void**)&data_out, sizeof(cufftComplex)*NX*(NY+2));

 /* Create a 2D FFT plan. */
cufftPlanMany(&plan, NRANK, n,NULL, 1, 0,NULL, 1, 0,CUFFT_C2C,BATCH);
cufftSetCompatibilityMode(plan, CUFFT_COMPATIBILITY_NATIVE);
cufftExecC2C(plan, data, data_out, CUFFT_FORWARD);
cudaThreadSynchronize();
cudaError  cudaStat2 = cudaMemcpy(c, data_out, sizeof(cufftComplex)*NX*(NY+2) , cudaMemcpyDeviceToHost);

cout << cudaGetErrorString(cudaStat2) << " ,\n";

for (int i = 0; i < NX; i++)
    {
    for (int j =0 ; j< NY; j++)
        {
        printf(" %f ,",c[i][j].x);

        }
    printf("\n");
    }

现在,输出设备矩阵为2 x sizeof(cufftComplex) NX (NY / 2 + 1),我已将其声明为data_out。 然后,还调整了主机端矩阵以容纳float2的NX *(NY + 2)元素。 现在,我没有从cudaMemcpy得到任何错误。 但是我仍然没有得到答案。 我得到的是1.#QNAN0值的数组。

那么我该如何解决呢?

通过进行我在注释中描述的修改,可以解决问题标题中描述的问题。 之后,您的代码还有其他问题,与结果的复制无关。

您正在请求大小为NX*NY的C2C转换,但您的输入数据大小仅为sizeof(cufftComplex)*NX*(NY/2+1) 当我解决输入数据及其大小的各种问题时,我开始得到的结果不是代码中的NAN。

另外,我不清楚您为什么要在各个位置分配大小(NY+2) 当我修复这些错误时,我可以从您的代码中得到某种(非NAN)结果:

$ cat t311.cu
#define NRANK 2
#define BATCH 10

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cufft.h>
#include <stdio.h>

#include <iostream>
#include <vector>

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)


using namespace std;


float func(int,int){
              return 2.0f;  // some value get return. I have put a dummy value here
}
int main()
    {

    const size_t NX = 4;
    const size_t NY = 5;

    // Input array - host side
    float **a = new float*[NX];

    for (int r = 0; r < NX; ++r)  // this can be also done on GPU
        {
        a[r] = new float[NY];
        for (int c = 0; c < NY; ++c)
            {
                a[r][c] = func(r,c);
            }
        }

    // Output array - host side
    float2 c[NX][NY] ;
    cufftHandle plan;

    cufftComplex *data;   // Input and output arrays - device side
    int n[NRANK] = {NX, NY};
    cudaMalloc((void**)&data, sizeof(cufftComplex)*NX*NY);
    cudaMemset(data,0, sizeof(cufftComplex)*NX*NY);
    for(int i=0; i<NX; ++i){
        cudaMemcpy(reinterpret_cast<float*>(data) + i*NY, a[i], sizeof(float)*NY,cudaMemcpyHostToDevice);
        cudaCheckErrors("cudaMemcpy H2D fail");
     }

  // New device side variable that will hold the result from the FFT size - twice as input {2 x NX*(NY/2 + 1)}
    cufftComplex *data_out;
    cudaMalloc((void**)&data_out, sizeof(cufftComplex)*NX*(NY));
    cudaCheckErrors("cudaMalloc data_out fail");
   /* Create a 2D FFT plan. */
    if ((cufftPlanMany(&plan, NRANK, n,NULL, 1, 0,NULL, 1, 0,CUFFT_C2C,BATCH)) != CUFFT_SUCCESS) printf("cufft fail 1\n");
    if ((cufftSetCompatibilityMode(plan, CUFFT_COMPATIBILITY_NATIVE)) != CUFFT_SUCCESS) printf("cufft fail 2\n");
    if ((cufftExecC2C(plan, data, data_out, CUFFT_FORWARD)) != CUFFT_SUCCESS) printf("cufft fail 3\n") ;
    cudaDeviceSynchronize();
    cudaMemcpy(c, data_out, sizeof(cufftComplex)*NX*(NY) , cudaMemcpyDeviceToHost);
    cudaCheckErrors("cudaMemcpy D2H fail");

    for (int i = 0; i < NX; i++)
      {
      for (int j =0 ; j< NY; j++)
        {
        printf(" %f ,",c[i][j].x);

        }
      printf("\n");
      }

    cufftDestroy(plan);
    cudaFree(data);
    cudaCheckErrors("some error");
    return 0;
    }

$ nvcc -arch=sm_20 -o t311 t311.cu -lcufft
$ ./t311
 20.000000 , 0.000000 , 0.000000 , 0.000000 , 0.000000 ,
 20.000000 , 0.000000 , 0.000000 , 0.000000 , 0.000000 ,
 0.000000 , 0.000000 , 0.000000 , 0.000000 , 0.000000 ,
 0.000000 , 0.000000 , 0.000000 , 0.000000 , 0.000000 ,
$

我并不是说这可以解决此代码可能存在的每个问题或错误,但是已经解决了您确定的前两个问题。

我认为剩下的问题源于如何填充输入数据。 您将不均匀数量(NY = 5)的浮点值放在cufftComplex数组的顶部。 对我来说,这会带来奇怪的结果。 每行(数据)的前两个复数值将具有2的实数和复数分量。第三个值将具有2的实数分量和一个虚数分量0。最后两个复数值将全部为零。

如果你想看到一个可能的方法以数组复制float值到复数值数组与单个API调用的实部,考虑cudaMemcpy2D ,记录在这里 ,用一个最近的例子在这里 该示例实际上显示了如何从结构数组复制到float数组,但是进行相反的操作(将float数组复制到structure数组)则使用了类似的技术。 这样的事情应该起作用:

for(int i=0; i<NX; ++i){
    cudaMemcpy2D(data + i*NY, sizeof(cufftComplex), a[i], sizeof(float), sizeof(float), NY, cudaMemcpyHostToDevice);
 }

如果您有新问题/新问题,请发布新的SO问题来描述它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM