对于我的论文,我必须使用CUDA优化一个特殊的MPI-Navier Stokes-Solver程序。原始程序使用FFTW来解决几个PDE。详细地,几个上三角矩阵在二维中被傅立叶变换,但是作为一维阵列处理。目前,我正在努力处理部分原始代码:( N总是设置为64)
原件:
//Does the complex to real in place fft an normalizes
void fftC2R(double complex *arr) {
fftw_execute_dft_c2r(plan_c2r, (fftw_complex*)arr, (double*)arr);
//Currently ignored: Normalization
/* for(int i=0; i<N*(N/2+1); i++)
arr[i] /= (double complex)sqrt((double complex)(N*N));*/
}
void doTimeStepETDRK2_nonlin_original() {
//calc velocity
ux[0] = 0;
uy[0] = 0;
for(int i=1; i<N*(N/2+1); i++) {
ux[i] = I*kvec[1][i]*qvec[i] / kvec[2][i];
uy[i] = -I*kvec[0][i]*qvec[i] / kvec[2][i];
}
fftC2R(ux);
fftC2R(uy);
//do some stuff here...
//...
return;
}
将ux和uy分配为(双复数组):
ux = (double complex*)fftw_malloc(N*(N/2+1) * sizeof(double complex));
uy = (double complex*)fftw_malloc(N*(N/2+1) * sizeof(double complex));
fft-plan创建为:
plan_c2r = fftw_plan_dft_c2r_2d(N, N,(fftw_complex*) qvec, (double*)qvec, FFTW_ESTIMATE);
其中qvec的分配方式与ux和uy相同,并且数据类型为double complex。
以下是CUDA代码的相关部分:
NN2_VecSetZero_and_init<<<block_size,grid_size>>>();
cudaSafeCall(cudaDeviceSynchronize());
cudaSafeCall(cudaGetLastError());
int err = (int)cufftExecZ2D(cu_plan_c2r,(cufftDoubleComplex*)sym_ux,(cufftDoubleReal*)sym_ux);
if (err != CUFFT_SUCCESS ) {
exit(EXIT_FAILURE);
return;
}
err = (int)cufftExecZ2D(cu_plan_c2r,(cufftDoubleComplex*)sym_uy,(cufftDoubleReal*)sym_uy);
if (err != CUFFT_SUCCESS ) {
exit(EXIT_FAILURE);
return;
}
//do some stuff here...
//...
return;
将sim_ux和sim_uy分配为:
cudaMalloc((void**)&sym_ux, N*(N/2+1)*sizeof(cufftDoubleComplex));
cudaMalloc((void**)&sym_uy, N*(N/2+1)*sizeof(cufftDoubleComplex));
相关袖口部件的初始化看起来像
if (cufftPlan2d(&cu_plan_c2r,N,N, CUFFT_Z2D) != CUFFT_SUCCESS){
exit(EXIT_FAILURE);
return -1;
}
if (cufftPlan2d(&cu_plan_r2c,N,N, CUFFT_D2Z) != CUFFT_SUCCESS){
exit(EXIT_FAILURE);
return -1;
}
if ( cufftSetCompatibilityMode ( cu_plan_c2r , CUFFT_COMPATIBILITY_FFTW_ALL) != CUFFT_SUCCESS ) {
exit(EXIT_FAILURE);
return -1;
}
if ( cufftSetCompatibilityMode ( cu_plan_r2c , CUFFT_COMPATIBILITY_FFTW_ALL) != CUFFT_SUCCESS ) {
exit(EXIT_FAILURE);
return -1;
}
所以我使用完全的FFTW兼容性,我用FFTW调用模式调用每个函数。
当我运行两个版本时,我收到的ux和uy(sim_ux和sim_uy)的结果差不多。但是在阵列的周期性位置,Cufft似乎忽略了这些元素,其中FFTW将这些元素的实部设置为零并计算复杂的部分(数组太大而无法在此处显示)。发生这种情况的步骤数是N / 2 + 1。所以我相信,我并没有完全理解Cufft和FFTW之间的fft-padding理论。
在调用Cufft-executions之前,我可以排除这些数组之间的任何先前的差异。所以上面代码的任何其他数组都不相关
我的问题是:我是否过于乐观地使用几乎100%的FFTW呼叫方式?我必须在ffts之前处理我的阵列吗? Cufft文档说,我必须调整数据输入和输出数组的大小。但是,当我在进行原地转换时,我怎么能这样做呢?我真的不想离原始代码太远了,我不想再为每个fft调用使用复制指令,因为内存有限,数组应该尽可能长时间地保留并在gpu上处理。 / p>
我很感谢每一个提示,批评声明或想法!
我的配置:
答案 0 :(得分:1)
一旦我与CUFFT有关,我开始工作的唯一解决方案是独家使用“cu_plan_c2c” - 真实和复杂数组之间有简单的转换:
- 使用0填充复杂零件以模拟cu_plan_r2c
-use atan2(not atan)对复杂结果进行模拟cu_plan_c2r
很抱歉没有指出任何更好的解决方案,但这就是我最终解决这个问题的方法。希望你没有进入任何低内存cpu侧的硬盘....