CUDA为开发人员提供了多种库,每一类库针对某一特定领域的应用,CUFFT库则是CUDA中专门用于进行傅里叶变换的函数库,这一系列的文章是博主近一段时间对cuFFT库的学习总结,主要内容是文档的译文,其间夹杂一些博主自己的理解。初学CUDA,理解有误之处在所难免,阅读本篇文章的读者如若发现请不吝指正。
cuFFT是的全称是CUDA Fast Fourier Transform,顾名思义,它提供了一系列的函数帮助开发者进行快速傅里叶变换的运算。cuFFT库由两个子库构成,它们分别是CUFFT和CUFFTW。CUFFTW库是一个移植工具(porting tool),它为用户提供了一些接口,以使得用户使用FFTW库(一个非常流行的CPU快速傅里叶变换库)编写的程序能够运行在CUDA GPU上。而CUFFT则是纯CUDA接口的快速傅里叶变换库。
在CUDA toolkit 5.5版本中,cuFFT库支持的特性有:
1、对于可以表示为的输入规模,CUFFT会自动采用一些优化算法来达到最佳的运算性能
2、对于所有的输入规模,CUFFT的算法复杂性均为O(nlogn)
3、不同输入输出类型的指定:其中C2C代表输入输出均为复数,R2C代表输入为实数而输出为复数,C2R代表输入为复数而输出为实数。
4、可以进行1维、2维和3维变换
5、多个不同的1D、2D、3D变换可以并行进行
6、同时支持单精度浮点和双精度浮点运算
7、支持就地转换(输出直接覆盖输入)和外部转换(输出和输入不重叠)
8、与FFTW库兼容的数据布局
9、支持跨步输入数据读取
10、支持流执行(Streamed execution),这样就同时支持了计算与数据传输的异步并行执行。
11、对于单精度浮点数,一次最多传输128百万元素,双精度则一次最多传输64百万元素。
12、CUFFT库提供的API是线程安全的。
#define NX 256 #define BATCH 10 ... { cufftHandle plan; cufftComplex *data; ... cudaMalloc((void**)&data, sizeof(cufftComplex)*NX*BATCH); cufftPlan1d(&plan, NX, CUFFT_C2C, BATCH); ... cufftExecC2C(plan, data, data, CUFFT_FORWARD); cudaThreadSynchronize(); ... cufftDestroy(plan); cudaFree(data); }
CUFFT和CUFFTW均被实现为共享库,可以使用编译器和链接器把它们集成到普通的程序当中。这些库文件和头文件在不同系统上的默认位置如下图所示:
最常见的使用这些库函数的方法是修改一个已经存在的CUDA文件,以filename.cu为例,在filename.cu中将头文件cufft.h包含进来,然后在程序中调用CUFFT库函数,为了使得程序可以运行,一个单一文件的编译和链接命令的形式可以如下:
CUFFT库实现了三种不同类型的傅里叶变换:C2C(复数到复数)、C2R(复数到实数)、R2C(实数到复数)。本质上,这三种转换都可以被看做是复数域到复数域的变换,之所以这样划分,其最主要的考量是性能因素。例如,在一般的数字信号处理中,输入数据是一些离散的实数域上的采样点,这时候对它们做傅里叶变换实际上就是R2C,根据埃尔米特对称性(Hermitian symmetry),变换后,*代表共轭复数。CUFFT的傅里叶变换类型则利用了这些冗余,将计算量降到最低。
变换执行函数的单精度和双精度版本分别定义如下:
1. cufftExecC2C() / cufftExecZ2Z() - 单精度/双精度浮点数复数域到复数域的傅里叶变换
2. cufftExecR2C() / cufftExecD2Z() - 单精度/双精度浮点数实数域到复数域的傅里叶变换(正向傅里叶变换)
3. cufftExecC2R() / cufftExecZ2D() - 单精度/双精度浮点数复数域到实数域的傅里叶变换(逆向傅里叶变换)
CUFFT库从版本4.1开始拥有线程安全特性,也就是说,主机端的多个线程同时调用CUFFT中的函数时,CUDA可以保证任务执行的正确性。