![](/img/trans.png)
[英]How to effectively copy data from 2D host array (with padding) to 1D device array and remove the original padding in 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.