欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > 【ELF2开发板】在 RK3588 上利用 VkFFT 实现基于 GPU 的 FFT 计算

【ELF2开发板】在 RK3588 上利用 VkFFT 实现基于 GPU 的 FFT 计算

2025/9/20 16:13:52 来源:https://blog.csdn.net/bit_mike/article/details/147431118  浏览:    关键词:【ELF2开发板】在 RK3588 上利用 VkFFT 实现基于 GPU 的 FFT 计算

引言

在数字信号处理领域,快速傅里叶变换(FFT)是一种极为重要的算法,它能够将时域信号转换为频域信号,广泛应用于音频处理、图像处理、通信等多个领域。前面几篇博客已经分享了一些CPU计算FFT的内容。随着硬件性能的不断提升,利用图形处理器(GPU)加速 FFT 计算成为提高处理效率的有效方式。今天,我们就来探讨一下如何在ELF2开发板上,借助VkFFT 库实现基于 GPU 的 FFT 计算。

VkFFT简介

VkFFT 是一个基于 Vulkan API 的快速傅里叶变换库。Vulkan 是新一代的跨平台图形和计算 API,它提供了高性能、低开销的设备访问,允许开发者直接控制 GPU 资源,实现更高效的并行计算。VkFFT 充分利用 Vulkan 的并行计算能力,将 FFT 计算任务分配到 GPU 的多个计算单元上同时执行,极大地提升了 FFT 计算的速度,特别适合处理大规模数据的 FFT 运算。

前面的博文介绍过RK3588 集成了 ARM Mali-G610 MP4 GPU,这款 GPU 具备强大的并行计算能力。要充分发挥GPU的计算能力,可以使用 OpenCL库。VkFFT 支持多种API,包括Vulkan/CUDA/HIP/OpenCL/Level Zero/Metal,所以也可以在RK3588平台上运行。

RK3588 上利用 VkFFT 实现 FFT 计算的步骤

下载与编译 VkFFT库

​从 VkFFT 的官方代码仓库(GitHub - DTolm/VkFFT: Vulkan/CUDA/HIP/OpenCL/Level Zero/Metal Fast Fourier Transform library)下载最新版本的代码。在下载完成后,进入VkFFT 的源代码目录,创建一个build目录用于存放编译生成的文件。使用cmake工具生成编译配置文件,例如:​​

mkdir build​
cd build​
cmake -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DVKFFT_BACKEND=3 \-DOpenCL_INCLUDE_DIR=../../opencltest/OpenCL-Headers-2020.03.13 \-D OpenCL_LIBRARY=../../opencltest/lib/libmali.so \-DCMAKE_EXE_LINKER_FLAGS="-Wl,--allow-shlib-undefined" ..

上述命令会根据系统环境和 VkFFT的配置文件生成相应的 Makefile。然后,使用make命令进行编译:​

make​

​编译完成后,会在build目录下生成 VkFFT测试程序,可以在开发板上测试效果。

VkFFT是一个只有头文件组成的库,编译后不会生成静态或动态库。

测试程序运行结果

下面是部分运行结果。

我也尝试了进行2048点的运算,结果如下:

root@elf2-buildroot:~# ./VkFFT_TestSuite -benchmark_vkfft -X 2048
arm_release_ver: g13p0-01eac0, rk_so_ver: 10
VkFFT System: 2048x1x1 Batch: 1 Buffer: 0 MB avg_time_per_step: 0.909 ms std_error: 0.268 num_iter: 1 benchmark: 17 scaled bandwidth: 0.1 real bandwidth: 0.1

这个时间明显是比前面的CPU测试要长的,这主要是因为2048点FFT太短了,它没法发挥GPU的优势,而CPU和GPU之间的数据传输和GPU调度的开销显得非常大。 

编写 FFT 计算应用程序

我尝试使用DeepSeek生成程序,不过它不完全正确,下面是修改后的程序。程序中没有包括填充数据的部分。

#define VKFFT_BACKEND 3  // 设置为OpenCL后端
#include <vkFFT.h>
#include <CL/cl.h>
#include <iostream>
#include <vector>
#include <chrono>int main() {const uint64_t fftSize = 2048;      // FFT点数uint64_t bufferSize = fftSize * 2 * sizeof(float);  // 复数数据大小// OpenCL初始化cl_platform_id platform;cl_device_id device;cl_context context;cl_command_queue queue;cl_int err;// 获取第一个OpenCL平台err = clGetPlatformIDs(1, &platform, NULL);if (err != CL_SUCCESS) {std::cerr << "获取OpenCL平台失败: " << err << std::endl;return 1;}// 获取第一个GPU设备err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);if (err != CL_SUCCESS) {std::cerr << "获取OpenCL设备失败: " << err << std::endl;return 1;}// 创建OpenCL上下文context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);if (!context) {std::cerr << "创建OpenCL上下文失败: " << err << std::endl;return 1;}// 创建命令队列queue = clCreateCommandQueue(context, device, 0, &err);if (!queue) {std::cerr << "创建命令队列失败: " << err << std::endl;return 1;}// 配置VkFFTVkFFTConfiguration config = {};config.FFTdim = 1;         // 1D FFTconfig.size[0] = fftSize;  // FFT点数config.doublePrecision = 0; // 单精度config.performR2C = 0;      // 复数输入输出config.normalize = 0;       // 不进行归一化config.bufferSize = &bufferSize;// OpenCL相关配置config.context = &context;config.device = &device;config.commandQueue = &queue;VkFFTApplication app = {};VkFFTResult res = initializeVkFFT(&app, config);if (res != VKFFT_SUCCESS) {std::cerr << "VkFFT初始化失败: " << res << std::endl;return 1;}// 创建OpenCL缓冲区cl_mem buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, bufferSize, NULL, &err);if (!buffer) {std::cerr << "创建缓冲区失败: " << err << std::endl;return 1;}// 创建启动参数VkFFTLaunchParams launchParams = {};launchParams.buffer = &buffer;launchParams.commandQueue = config.commandQueue;// 执行FFT并计时auto start = std::chrono::high_resolution_clock::now();res = VkFFTAppend(&app, -1, &launchParams); // 正变换if (res != VKFFT_SUCCESS) {std::cerr << "FFT执行失败: " << res << std::endl;return 1;}clFinish(queue); // 等待操作完成auto end = std::chrono::high_resolution_clock::now();// 计算耗时auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);std::cout << "FFT执行时间: " << duration.count() << " 微秒" << std::endl;// 清理资源clReleaseMemObject(buffer);deleteVkFFT(&app);clReleaseCommandQueue(queue);clReleaseContext(context);return 0;
}

 程序可以用下面的命令编译:

aarch64-linux-gnu-g++ -std=c++17 test.cpp -o vkfft_ocl -lmali \-I../../opencltest/OpenCL-Headers-2020.03.13 \-L../../opencltest/lib/  -Wl,--allow-shlib-undefined -I../vkFFT/

结语

在 RK3588 上利用 VkFFT 实现基于 GPU 的 FFT 计算,提供了一种新的计算方式。

然而,在实际应用中,也需要注意一些问题。例如数据传输的开销,在将数据从 CPU 内存传输到 GPU 内存以及将计算结果从 GPU 内存传输回 CPU 内存的过程中,会存在一定的时间开销,需要合理优化数据传输策略。​

总的来说,VkFFT为在 RK3588 等具备强大 GPU 的设备上实现高效的 FFT 计算提供了有力的工具。通过合理的环境搭建、库使用和程序优化,我们能够充分发挥 GPU 的并行计算优势,提升数字信号处理应用的性能。如果你对 GPU 加速计算和 FFT 算法感兴趣,不妨尝试在 RK3588 上使用 VkFFT 进行实践,探索更多的应用可能性。​

以上就是在RK3588 上利用VkFFT实现基于 GPU 的 FFT 计算的详细介绍。如果你在实践中有任何问题,或者想了解更多相关内容,欢迎在评论区留言交流。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词