Intel 黑客松-实现2D-FFT

简介

Intel这次的黑客松比赛要求利用OneAPIMKL库,生成2048*2048的单精度数,然后利用内部库实现FFT变换,因为MKL内部整合了fftw3这个库,所以我分别用其内部的库跟自带的fftw3进行对比。最后是对比两种FFT的结果。

生成单精度实数

生成单精度数的代码如下,这里面全是MKL自带的函数,非常好用,建议各位阅读一下Intel的函数说明,会对这些函数有一个进一步的理解,我直接把这些函数的说明文档链接贴出来(就不当翻译了)

void generate_random_array(float* array, int N1, int N2)
{
    MKL_UINT seed = 123;
    VSLStreamStatePtr stream;
    vslNewStream(&stream, VSL_BRNG_MT19937, seed);
    vsRngUniform(VSL_RNG_METHOD_UNIFORM_STD, stream, N1 * N2, array, 0.0, 10.0);
    vslDeleteStream(&stream);
}

这里,注意图中我画框的地方,可以直接搜索需要了解的函数名字,很方面,很直接。

利用fftw3实现FFT

核心代码如下:

void fftw3(float* Datain, fftwf_complex* Dataout, int N1, int N2)
{
    fftwf_plan stream = NULL;
    stream = fftwf_plan_dft_r2c_2d(N1, N2, Datain, Dataout, FFTW_ESTIMATE);
    fftwf_execute(stream);
    fftwf_destroy_plan(stream);
}

这里与后面直接调用MKL不同的是注意输出数据类型的定义,即这句代码

fftwf_complex* Dataout

利用MKL实现FFT

核心代码如下:

void MKL_2Dfft(float* Datain, MKL_Complex8* Dataout, int N1, int N2)
{
    MKL_LONG dims[2] = { N2, N1 };
    MKL_LONG status = 0;
    MKL_LONG rstrides[] = { 0, N1, 1 };
    MKL_LONG cstrides[] = { 0, N1 / 2 + 1, 1 };
    DFTI_DESCRIPTOR_HANDLE hand = NULL;
    char version[DFTI_VERSION_LENGTH];

    //Basic MLK functions
    DftiGetValue(0, DFTI_VERSION, version);
    status = DftiCreateDescriptor(&hand, DFTI_SINGLE, DFTI_REAL, 2, dims);
    status = DftiSetValue(hand, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
    status = DftiSetValue(hand, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX);
    status = DftiSetValue(hand, DFTI_INPUT_STRIDES, rstrides);
    status = DftiSetValue(hand, DFTI_OUTPUT_STRIDES, cstrides);
    status = DftiCommitDescriptor(hand);
    status = DftiComputeForward(hand, Datain, Dataout);
    DftiFreeDescriptor(&hand);
    
}

这里我写了注释,那些status,请各位看一下Intel的函数说明,特别注意的是这些代码几乎是最简版本,当然由于本人学艺不精,所以还有会有更好的写法。另外注意这里输出的数据是这样的数据类型。

MKL_Complex8* Dataout

调用及结果对比

主函数中,主要需要注意的就是,在定义FFTW和MKL的输入输出的数据类型时,其他的部分全是基础。

int main(int argc, char *argv[])
{
    int rows = 2048, cols = 2048;
    float* random_array = (float*)malloc(rows * cols * sizeof(float));

    // Call the function to generate a random array
    generate_random_array(random_array, rows, cols);

    float* fftw3_input = (float*)fftwf_malloc(rows * cols * sizeof(float));
    fftwf_complex* fftw3_output = (fftwf_complex*)fftwf_malloc((cols)*rows * sizeof(fftwf_complex));
    float* mkl_input_real = (float*)mkl_malloc(rows * cols * sizeof(float), 64);
    MKL_Complex8* mkl_output_cmplx = (MKL_Complex8*)mkl_malloc(rows * cols * sizeof(MKL_Complex8), 64);
    for (int j = 0; j < rows * cols; j++)
    {
        mkl_input_real[j] = random_array[j];
        fftw3_input[j] = random_array[j];
    }
    
    
    int times = atoi(argv[1]); // Set the number of iterations
    printf("we will run %d times \n", times);
    
    //Perform MKL FFT
    clock_t start_time_mkl = clock();
    for (int t=0;t<times;t++){
        MKL_2Dfft(mkl_input_real, mkl_output_cmplx, rows, cols);
    }
    clock_t end_time_mkl = clock();
    float total_time_mkl = (float)(end_time_mkl - start_time_mkl) / CLOCKS_PER_SEC;
    printf("performFFT_oneMKL total time: %f s \n", total_time_mkl);
    //Perform FFTW fft
    clock_t start_time_FFTW = clock();
    for (int t=0;t<times;t++){
        fftw3(fftw3_input, fftw3_output, rows, cols);
    }
    clock_t end_time_FFTW = clock();
    float total_time_FFTW = (float)(end_time_FFTW - start_time_FFTW) / CLOCKS_PER_SEC;
    printf("performFFT_fftw total time: %f s \n", total_time_FFTW);


    // test the rusults
    float error_real = 0.0, error_imag = 0.0, maxerr = 0.001, total_error_real = 0.0, total_error_imag = 0.0;
    for (int k = 0; k < rows*cols; k++)
    {
        error_real = fabsf(fftw3_output[k][0] - mkl_output_cmplx[k].real);
        error_imag = fabsf(fftw3_output[k][1] - mkl_output_cmplx[k].imag);
        if (error_real > maxerr || error_imag > maxerr)
        {
            printf("Result is inconsistan: ");
            printf("%d\n", k);
        }
        total_error_real = total_error_real + error_real;
        total_error_imag = total_error_imag + error_imag;
    }
    if (error_real < maxerr && error_imag < maxerr)
    {
        printf("Result is consistant\n");
        printf("\n");
    }
    printf("Here are average errors: \n");
    printf("Error of real part is:%f Error of image part is:%f%s\n", total_error_real / (rows * cols),   total_error_imag / (rows * cols), "i");
    printf("\n");
    
    //Free memory
    mkl_free(mkl_input_real);
    mkl_free(mkl_output_cmplx);
    free(random_array);
    fftwf_free(fftw3_input);
    fftwf_free(fftw3_output);
}

最后输出的结果如下:

通过结果来看,在运行400次的时候,fftw还是比MKL要快,但是小于400次,MKL的速度是远远大于fftw的,但是一旦大于400次,fftw的速度就超过MKL了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值