gpt4 book ai didi

c++ - 如何在 Cuda 中将二维数组从设备复制到主机?

转载 作者:行者123 更新时间:2023-11-28 07:12:06 29 4
gpt4 key购买 nike

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

事情是这样的。输入是指向 float 指针的指针。这些值在运行时分配。然后将其传输到gpu并计算fft。然后传输结果到 float2 二维数组。但是我得到的结果是错误的。它包含全零。那么我该如何克服这个问题呢?

#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。最后两个复数值将为全零。

如果您想了解一种通过单个 API 调用将 float 值数组复制到复数值数组的实部的可能方法,请考虑 cudaMemcpy2D , 记录在案 here和最近的例子 here .该示例实际上展示了如何从结构数组复制到 float 数组,但反向操作(float 数组到结构数组)使用了类似的技术。这样的事情应该有效:

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

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

关于c++ - 如何在 Cuda 中将二维数组从设备复制到主机?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20811679/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com