【问题标题】:running FFTW on GPU vs using CUFFT在 GPU 上运行 FFTW 与使用 CUFFT
【发布时间】:2013-05-27 20:37:36
【问题描述】:

我有一个基本的 C++ FFTW 实现,如下所示:

for (int i = 0; i < N; i++){
     // declare pointers and plan
     fftw_complex *in, *out;
     fftw_plan p;

     // allocate 
     in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
     out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);

     // initialize "in"
     ...

     // create plan
     p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);

     // execute plan
     fftw_execute(p);

     // clean up
     fftw_destroy_plan(p);
     fftw_free(in); fftw_free(out);
}

我在 for 循环中做了 N 个 fft。我知道我可以使用 FFTW 一次执行多个计划,但是在我的实现中 inout 每个循环都不同。关键是我在 for 循环中执行整个 FFTW 管道。

我想过渡到使用 CUDA 来加快速度。我知道 CUDA 有自己的 FFT 库 CUFFT。语法非常相似:来自他们的online documentation

#define NX 64
#define NY 64
#define NZ 128

cufftHandle plan;
cufftComplex *data1, *data2;
cudaMalloc((void**)&data1, sizeof(cufftComplex)*NX*NY*NZ);
cudaMalloc((void**)&data2, sizeof(cufftComplex)*NX*NY*NZ);
/* Create a 3D FFT plan. */
cufftPlan3d(&plan, NX, NY, NZ, CUFFT_C2C);

/* Transform the first signal in place. */
cufftExecC2C(plan, data1, data1, CUFFT_FORWARD);

/* Transform the second signal using the same plan. */
cufftExecC2C(plan, data2, data2, CUFFT_FORWARD);

/* Destroy the cuFFT plan. */
cufftDestroy(plan);
cudaFree(data1); cudaFree(data2);

但是,这些“内核”中的每一个(正如 Nvida 所称)(cufftPlan3d、cufftExecC2C 等)都是与 GPU 之间的调用。如果我正确理解了 CUDA 结构,那么这些方法调用中的每一个都是单独并行化的操作:

#define NX 64
#define NY 64
#define NZ 128

cufftHandle plan;
cufftComplex *data1, *data2;
cudaMalloc((void**)&data1, sizeof(cufftComplex)*NX*NY*NZ);
cudaMalloc((void**)&data2, sizeof(cufftComplex)*NX*NY*NZ);
/* Create a 3D FFT plan. */
cufftPlan3d(&plan, NX, NY, NZ, CUFFT_C2C); // DO THIS IN PARALLEL ON GPU, THEN COME BACK TO CPU

/* Transform the first signal in place. */
cufftExecC2C(plan, data1, data1, CUFFT_FORWARD); // DO THIS IN PARALLEL ON GPU, THEN COME BACK TO CPU

/* Transform the second signal using the same plan. */
cufftExecC2C(plan, data2, data2, CUFFT_FORWARD); // DO THIS IN PARALLEL ON GPU, THEN COME BACK TO CPU

/* Destroy the cuFFT plan. */
cufftDestroy(plan);
cudaFree(data1); cudaFree(data2);

我了解这如何通过在 GPU 上运行每个 FFT 步骤来加速我的代码。但是,如果我想并行化整个 for 循环怎么办?如果我希望每个原始的 N 个 for 循环都在 GPU 上运行整个 FFTW 管道怎么办?我可以创建自定义“内核”并从设备 (GPU) 调用 FFTW 方法吗?

【问题讨论】:

  • 除了GPU的使用,我对基本的fftw使用有一点建议。仅将 fftw_execute 保留在循环内,并在 for 循环之前或之后移动任何其他 fftw 函数。立即执行内存分配并在循环内使用相同的内存,以便您可以在循环之前创建计划。同样,在 for 循环之后销毁计划并释放分配的内存。请注意,创建计划可能会在循环中浪费大量时间。

标签: cuda fftw cufft


【解决方案1】:

您不能从设备代码调用 FFTW 方法。 FFTW 库是编译的 x86 代码,不会在 GPU 上运行。

如果您的代码中的“繁重工作”在 FFT 操作中,并且 FFT 操作的规模相当大,那么只需按照指示调用 cufft 库例程即可为您提供良好的加速并大致充分利用机器。一旦机器被充分利用,尝试并行运行更多的东西通常没有额外的好处。

cufft 例程can be called by multiple host threads,因此可以对 cufft 进行多次调用以进行多个独立的转换。如果单个转换足够大以使用机器,您不太可能会看到由此带来的加速。

cufft 还支持batched plans,这是“一次”执行多个转换的另一种方式。

【讨论】:

  • 当您说“cufft 例程可以由多个主机线程调用,因此可以对 cufft 进行多次调用以进行多个独立转换。”你的意思是我可以用另一种方式并行化我的 for 循环(比如使用 openMP)?
  • 是的,我相信这应该是可能的。但是,我不确定它是否会提供很多加速。如果您正在寻找加速,您可能需要考虑使用cufft in cuda streams,这至少可以让您将数据复制与袖带处理重叠。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 1970-01-01
  • 1970-01-01
  • 2021-07-20
  • 1970-01-01
  • 2012-11-13
  • 2011-12-11
相关资源
最近更新 更多