1. 介绍
本文档介绍了沐曦 MXMACA® 快速傅立叶变换 (FFT) 产品 mcFFT。mcFFT库旨在为沐曦 GPU提供高性能支持。
FFT是一种分治算法,用于高效地计算复数或实数集的离散傅里叶变换。 它是计算物理学和通用信号处理中最重要、应用最广泛的数值算法之一。 mcFFT 库为在沐曦 GPU 上计算FFT提供了一个简单的接口,允许用户可以在高度优化和测试的FFT库中快速利用GPU的浮点计算能力和并行性。
mcFFT产品在沐曦 GPU上广泛且有效支持各种FFT输入和选项。该版本的mcFFT库支持以下功能:
高度优化的算法可以适用于形如 \(2^{a} \times 3^{b} \times 5^{c} \times 7^{d}\) 的输入数据上。通常来说,素数因子越小,性能越好。即,二次幂最快
\(O\left( n\log n \right)\) 算法适用于各种大小的输入数据
支持单精度(32bit 浮点数)和双精度(64bit浮点数)的FFT。低精度浮点数的FFT拥有更好的性能
支持复数和实数的输入和输出。实数输入输出和复数输入输出相比较而言,实数要求的算力更少并且处理速度更快。支持的类型包括:
C2C - 复数输入到复数输出的FFT
R2C - 实数输入到复数输出的FFT
C2R - 对称复数输入到实数输出的FFT
支持一维,二维和三维变换
支持复数个一维,二维和三维同时变换。和单个变换相比,批处理变换更加高效
支持原地变换和异地变换
支持任一维度内和维度间的元素步长(支持跨步布局)
支持流式执行。允许异步计算和数据传输
1.1. 安装mcFFT
mcFFT是随MXMACA工具包一起发布的库。MXMACA工具包的安装请参见《曦云系列通用GPU 快速上手指南》。安装完成后,请确保设置了环境变量MACA_PATH。
export MACA_PATH=/your/maca/path
mcFFT API 相关文档如下:
#header location:
${MACA_PATH}/include/mcfft
#lib location:
${MACA_PATH}/lib/libmcfft.so
${MACA_PATH}/lib/libmcfft-device-0.so
${MACA_PATH}/lib/libmcfft-device-1.so
${MACA_PATH}/lib/libmcfft-device-2.so
${MACA_PATH}/lib/libmcfft-device-3.so
1.2. Hello mcFFT
以下示例代码演示了使用mcFFT库API编写的C语言应用程序:
#CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(mcfft_samples)
if(NOT DEFINED ENV{MACA_PATH})
message(FATAL_ERROR "not defined environment variable: MACA_PATH")
endif()
INCLUDE_DIRECTORIES($ENV{MACA_PATH}/include/)
INCLUDE_DIRECTORIES($ENV{MACA_PATH}/include/mcfft/)
INCLUDE_DIRECTORIES($ENV{MACA_PATH}/mcr/)
LINK_DIRECTORIES($ENV{MACA_PATH}/lib)
set(LINK_LIBS
mc_runtime
mcfft
mcfft-device-0
mcfft-device-1
mcfft-device-2
mcfft-device-3
)
set(sample_list complex_1d)
foreach(sample ${sample_list})
add_executable(mcfft_${sample} ${sample}.cpp)
target_link_libraries(mcfft_${sample} ${LINK_LIBS})
endforeach()
//complex_1d.cpp, 1D, C2C, in-place
//-----------------------------------------------------------
#include <cassert>
#include <complex>
#include <iostream>
#include <vector>
#include <random>
#include <mc_runtime.h>
#include "mcfft.h"
#define NX 8
#define BATCH 1
int main(int argc, char* argv[])
{
std::cout << "mcFFT complex 1d FFT example\n";
mcfftHandle plan;
mcError_t err;
//在主机处初始化数据:
std::vector<std::complex<float>> data(NX*BATCH);
std::vector<std::complex<float>> outData(NX*BATCH);
std::cout << "Input:\n";
for(int b = 0; b < BATCH; b++)
{
for(int n = 0; b < NX; n++)
{
std::mt19937 gen(n);
const float x = (float)gen() / (float)gen.max();
const float y = (float)gen() / (float)gen.max();
const std::complex<float> val(x,y);
data[NX*b + n] = val;
std::cout<<data[NX*b + n]<<" ";
}
}
// 创建设备对象和计划:
mcfftComplex *devPtrData=nullptr;
err=mcMalloc((void**)&devPtrData, sizeof(mcfftComplex)*NX*BATCH);
if (err != mcSuccess)
{
fprintf(stderr, "Error: Failed to allocate\n");
return EXIT_FAILURE;
}
if (mcfftPlan1d(&plan, NX, MCFFT_C2C, BATCH) != mcSuccess)
{
fprintf(stderr, "mcFFT Error: Plan creation failed\n");
return EXIT_FAILURE;
}
//复制数据
err = mcMemcpy(devPtrData, data.data(), sizeof(mcfftComplex)*NX*BATCH, mcMemcpyHostToDevice);
if (err != mcSuccess)
{
fprintf(stderr, "Error: Failed to copy host to device\n");
return EXIT_FAILURE;
}
// 执行正向变换和原地变换
if (mcfftExecC2C(plan, devPtrData, devPtrData, MCFFT_FORWARD) != mcSuccess)
{
fprintf(stderr, "mcFFT error: ExecC2C Forward failed\n");
return EXIT_FAILURE;
}
// 执行逆向变换和原地变换
if (mcfftExecC2C(plan, devPtrData, devPtrData, MCFFT_INVERSE) != mcSuccess)
{
fprintf(stderr, "mcFFT error: ExecC2C Inverse failed\n");
return EXIT_FAILURE;
}
/*
* 在所有任务完成之前,可能无法立即获得结果
*
*/
if (mcDeviceSynchronize() != mcSuccess)
{
fprintf(stderr, "Error: Failed to synchronize\n");
return EXIT_FAILURE;
}
err = mcMemcpy(outData.data(), devPtrData, sizeof(mcfftComplex)*NX*BATCH, mcMemcpyDeviceToHost);
if (err != mcSuccess)
{
fprintf(stderr, "Error: Failed to copy device to host\n");
return EXIT_FAILURE;
}
const float overN = 1.0f / Nx;
float error = 0.0f;
for(size_t i = 0; i < data.size(); i++)
{
float diff = std::max(std::abs(data[i].real() - outData[i].real() * overN),
std::abs(data[i].imag() - outData[i].imag() * overN));
if(diff > error)
{
error = diff;
}
}
std::cout << "Transformed back:\n";
for(size_t i = 0; i < outData.size(); i++)
{
std::cout << outData[i]*overN << " ";
}
std::cout << std::endl;
std::cout << "Maximum error: " << error << "\n";
mcfftDestroy(plan);
mcFree(devPtrData);
}
上述文件(CMakeList.txt和complex_1d.cpp)在同一个目录中,比如 /your/example/path 。示例编译步骤如下:
$ cd /your/example/path
$ mkdir build && cd build
$ cmake ..
$ make