当前位置:   article > 正文

oneMKL与FFTW3对FFT2D加速对比_fftw fft2

fftw fft2

Github上某大佬的文章指出,Intel下的onemkL函数库对于大型矩阵的计算很厉害,如下图,在运算性能以及速度上优于诸多方法,本文旨在通过自己亲身实践,学习不同算法函数库用以求解二维实数到复数的快速傅里叶变换,文章最后会附带上全部源代码。(这是本人的第一篇文章,欢迎大家共同交流学习,共勉。)

oneMKL和FFTW3介绍

oneMKL

英特尔 ®oneAPI 数学内核库( Intel® oneAPI Math Kernel Library ,简称 oneMKL )是一
个计算数学库,其中包含高度优化的广泛线程例程,适用于需要最高性能的应用程序。该库
提供 Fortran C 编程语言接口。 oneMKLC 语言接口可以从用 C C++ 以及可以引用 C
口的任何其他语言编写的应用程序中调用。
oneMKL 在这些主要计算领域提供全面的功能支持:
01、BLAS (1 级、 2 级和 3 级)和 LAPACK 线性代数例程,提供向量、向量矩阵和矩
阵矩阵运算。
02、ScaLAPACK 分布式处理线性代数例程,以及基本线性代数通信子程序 (BLACS)
并行基本线性代数子程序 (PBLAS)
03、oneMKL PARDISO (基于并行直接稀疏求解器 PARDISO* 的直接稀疏求解器),迭
04、代稀疏求解器,支持用于求解稀疏方程组的稀疏 BLAS (1 2 3 级)例程,以及
分布式版本提供 oneMKL PARDISO 求解器用于集群。
05、 一维、二维或三维中的快速傅立叶变换 (FFT) 函数,支持混合基数(不限于 2 的幂
的大小),以及提供在集群上使用的这些函数的分布式版本。
06、用于优化向量数学运算的向量数学 (VM) 例程。
07、 矢量统计 (VS) 例程,为多种概率分布、卷积和相关例程以及汇总统计函数提供高性
能矢量化随机数生成器 (RNG)
08、 数据拟合库,提供基于样条的函数逼近、函数导数和积分以及搜索功能。
09、 扩展特征求解器,基于 Feast 特征值求解器的特征求解器的共享内存编程 (SMP)
本。
英特尔 ® oneAPI 数学核心库 (oneMKL) 针对英特尔处理器上的性能进行了优化。
oneMKL 还可以在非 Intel x86 兼容处理器上运行。
oneMKL 可以作为单独的软件包下载:
https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl-download.html
也可以作为 Intel® oneAPI Base Toolkit 的一部分下载:
https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit-download.html
进入到下载界面后,选择自己的操作系统以及在线或者离线安装方式之后,按照提示进行安
装即可。

FFTW3

FFTW3(Fastest Fourier Transform in the West)是一个开源的软件库,用于计算快速傅里叶变换(FFT)。它提供了高效的算法和实现,用于在数字信号处理、图像处理、模拟和科学计算等领域进行频率域分析。FFTW3被广泛应用于各种编程语言和平台上。它提供了多种不同的FFT变换算法,以适应不同的数据大小和性能需求。

实验环境配置

处理器:Intel i5

虚拟机:vwmare17,乌班图18.04(推荐使用,个人觉得比较稳定,出了问题网上可查的解决方法也较多,不过也不必纠结于版本,能跑就行)

代码实现

首先,调用oneMKL封装的函数,随机生成2048*2048大小的单精度浮点数:

  1. VSLStreamStatePtr stream;
  2. vslNewStream(&stream,VSL_BRNG_MT19937,1);
  3. vsRngUniform(VSL_RNG_METHOD_UNIFORM_STD,stream,Nx*Nz,input,0.0f,1.0f);
  4. vslDeleteStream(&stream);

使用FFTW3计算real to imag FFT2D:

  1. fftwf_complex *outputFFTW=(fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex)*Nx*(Nz/2+1));
  2. fftwf_plan status=fftwf_plan_dft_r2c_2d(Nx,Nz,input,outputFFTW,FFTW_MEASURE);
  3. t0=wallclock_time();
  4. fftwf_execute(status);
  5. t1=wallclock_time();

其中,wallclock_time()是自定义的时间函数,如下:

  1. double wallclock_time(void)
  2. {
  3. struct timeval s_val;
  4. static struct timeval b_val;
  5. double time;
  6. static int base=0;
  7. gettimeofday(&s_val,0);
  8. if (!base) {
  9. b_val = s_val;
  10. base = 1;
  11. return 0.0;
  12. }
  13. time = (double)(s_val.tv_sec-b_val.tv_sec) +
  14. (double)(1e-6*((double)s_val.tv_usec-(double)b_val.tv_usec));
  15. return (double)time;
  16. }

使用oneMKL计算real to imag FFT2D:

  1. MKL_LONG rs[3]={0,Nx,1};
  2. MKL_LONG cs[3]={0,Nz/2+1,1};
  3. MKL_Complex8 *outputMKL=(MKL_Complex8 *)malloc(sizeof(MKL_Complex8)*Nx*(Nz/2+1));
  4. DFTI_DESCRIPTOR_HANDLE handle;
  5. MKL_LONG sizeN[2]={Nx,Nz};
  6. DftiCreateDescriptor(&handle,DFTI_SINGLE,DFTI_REAL,2,sizeN);
  7. DftiSetValue(handle,DFTI_PLACEMENT,DFTI_NOT_INPLACE);
  8. DftiSetValue(handle,DFTI_CONJUGATE_EVEN_STORAGE,DFTI_COMPLEX_COMPLEX);
  9. DftiSetValue(handle,DFTI_INPUT_STRIDES,rs);
  10. DftiSetValue(handle,DFTI_OUTPUT_STRIDES,cs);
  11. DftiCommitDescriptor(handle);
  12. t0=wallclock_time();
  13. DftiComputeForward(handle,input,outputMKL);
  14. t1=wallclock_time();

比较残差以及运算性能:

  1. if(Nx==Nz)
  2. {
  3. printf("-------------------------\n");
  4. diff=0;
  5. for(i=0;i<Nx*(Nz/2+1);i++)
  6. {
  7. diff1=(double)fabs(outputMKL[i].real-outputFFTW[i][0]);
  8. diff2=(double)fabs(outputMKL[i].imag-outputFFTW[i][1]);
  9. if(diff1>0.000001 || diff2>0.000001)
  10. {
  11. diff=1;
  12. break;
  13. }
  14. }
  15. if(diff==0) fprintf(stderr," CORRECT (residual < 0.000001) bwetween FFTW3 with oneMKL\n");
  16. else fprintf(stderr," ERROR (residual >0.000001 ) bwetween FFTW3 with oneMKL\n");
  17. }

最终结果:

可以发现,oneMKL精度在0.000001数量级下与开源的FFTW3相同,同时性能更加优秀。(不同电脑配置加速率不一样)

全部源代码

按照如下方法编译,这要求你的环境上正确安装编译器。

icx fft_2d_r2c_fftw_and_onemkl.c -o fft_2d_r2c_fftw_and_onemkl -qmkl -std=c99 -lmkl_rt -lm

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<math.h>
  4. #include<time.h>
  5. #include<sys/time.h>
  6. #include<stdbool.h>
  7. #include<string.h>
  8. #include<sys/resource.h>
  9. #include<fftw3.h>
  10. #include<mkl.h>
  11. #include"mkl_vsl.h"
  12. #include"mkl_service.h"
  13. #include"mkl_dfti.h"
  14. size_t getCurrentMemoryUsage();
  15. double wallclock_time(void);
  16. int main(int argc,char *argv[])
  17. {
  18. int i,Nx,Nz;
  19. double t0,t1,t,k,diff1,diff2,diff;
  20. size_t memoryUsage;
  21. Nx=2048;
  22. Nz=2048;
  23. //N2=16;
  24. k=log(Nz)/log(2)+1;
  25. while(Nz<=Nx)
  26. {
  27. float *input=(float *)malloc(sizeof(float)*Nx*Nz);
  28. /*Random numbers*/
  29. VSLStreamStatePtr stream;
  30. vslNewStream(&stream,VSL_BRNG_MT19937,1);
  31. vsRngUniform(VSL_RNG_METHOD_UNIFORM_STD,stream,Nx*Nz,input,0.0f,1.0f);
  32. vslDeleteStream(&stream);
  33. /*Use FFTW3 to do FFT2d*/
  34. fftwf_complex *outputFFTW=(fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex)*Nx*(Nz/2+1));
  35. fftwf_plan status=fftwf_plan_dft_r2c_2d(Nx,Nz,input,outputFFTW,FFTW_MEASURE);
  36. t0=wallclock_time();
  37. fftwf_execute(status);
  38. t1=wallclock_time();
  39. t=t1-t0;
  40. fprintf(stderr," FFTW Plan N=(%-5d * %-5d) time is %f s\n",Nx,Nz,t);
  41. if(Nx==Nz)
  42. {
  43. t0=wallclock_time();
  44. for(i=0;i<1000;i++) fftwf_execute(status);
  45. t1=wallclock_time();
  46. t=t1-t0;
  47. fprintf(stderr," 1000 times FFTW Plan N=(%-5d * %-5d) time is %f s\n",Nx,Nz,t);
  48. }
  49. /*Use oneMKL to do FFT2d*/
  50. MKL_LONG rs[3]={0,Nx,1};
  51. MKL_LONG cs[3]={0,Nz/2+1,1};
  52. MKL_Complex8 *outputMKL=(MKL_Complex8 *)malloc(sizeof(MKL_Complex8)*Nx*(Nz/2+1));
  53. DFTI_DESCRIPTOR_HANDLE handle;
  54. MKL_LONG sizeN[2]={Nx,Nz};
  55. DftiCreateDescriptor(&handle,DFTI_SINGLE,DFTI_REAL,2,sizeN);
  56. DftiSetValue(handle,DFTI_PLACEMENT,DFTI_NOT_INPLACE);
  57. DftiSetValue(handle,DFTI_CONJUGATE_EVEN_STORAGE,DFTI_COMPLEX_COMPLEX);
  58. DftiSetValue(handle,DFTI_INPUT_STRIDES,rs);
  59. DftiSetValue(handle,DFTI_OUTPUT_STRIDES,cs);
  60. DftiCommitDescriptor(handle);
  61. t0=wallclock_time();
  62. DftiComputeForward(handle,input,outputMKL);
  63. t1=wallclock_time();
  64. t=t1-t0;
  65. fprintf(stderr," oneMKL Plan N=(%-5d * %-5d) time is %f s\n",Nx,Nz,t);
  66. if(Nx==Nz)
  67. {
  68. t0=wallclock_time();
  69. for(i=0;i<1000;i++) DftiComputeForward(handle,input,outputMKL);
  70. t1=wallclock_time();
  71. t=t1-t0;
  72. fprintf(stderr," 1000 times oneMKL Plan N=(%-5d * %-5d) time is %f s\n",Nx,Nz,t);
  73. }
  74. /*Compare oneMKL and FFTW3*/
  75. if(Nx==Nz)
  76. {
  77. printf("-------------------------\n");
  78. diff=0;
  79. for(i=0;i<Nx*(Nz/2+1);i++)
  80. {
  81. diff1=(double)fabs(outputMKL[i].real-outputFFTW[i][0]);
  82. diff2=(double)fabs(outputMKL[i].imag-outputFFTW[i][1]);
  83. if(diff1>0.000001 || diff2>0.000001)
  84. {
  85. diff=1;
  86. break;
  87. }
  88. }
  89. if(diff==0) fprintf(stderr," CORRECT (residual < 0.000001) bwetween FFTW3 with oneMKL\n");
  90. else fprintf(stderr," ERROR (residual >0.000001 ) bwetween FFTW3 with oneMKL\n");
  91. }
  92. free(input);
  93. free(outputMKL);
  94. DftiFreeDescriptor(&handle);
  95. //fftwf_destory_plan(status);
  96. fftwf_free(outputFFTW);
  97. Nz=pow(2.0,k);
  98. k+=1.0;
  99. }
  100. memoryUsage = getCurrentMemoryUsage();
  101. fprintf(stderr," CPU usage size : %zu KB \n",memoryUsage);
  102. return 0;
  103. }
  104. size_t getCurrentMemoryUsage(){
  105. struct rusage usage;
  106. getrusage(RUSAGE_SELF, &usage);
  107. return usage.ru_maxrss;
  108. }
  109. double wallclock_time(void)
  110. {
  111. struct timeval s_val;
  112. static struct timeval b_val;
  113. double time;
  114. static int base=0;
  115. gettimeofday(&s_val,0);
  116. if (!base) {
  117. b_val = s_val;
  118. base = 1;
  119. return 0.0;
  120. }
  121. time = (double)(s_val.tv_sec-b_val.tv_sec) +
  122. (double)(1e-6*((double)s_val.tv_usec-(double)b_val.tv_usec));
  123. return (double)time;
  124. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/105113
推荐阅读
相关标签
  

闽ICP备14008679号