目錄
引言
OpenMP簡介
編譯OpenMP支持的FFTW庫
部署與測試
測試程序
程序部署
測試結果
結語
引言
在前面已經介紹了在ELF2開發板上運行FFTW計算FFT。今天嘗試利用RK3588的多核運算能力來加速FFT運算。FFTW利用多核能力可以考慮使用多線程或者OpenMP。今天介紹一下OpenMP的測試結果。
OpenMP簡介
OpenMP(Open Multi-Processing)是一種基于共享內存的并行編程模型,旨在簡化多核CPU的并行計算開發。它通過編譯器指令(Compiler Directives)、運行時庫函數和環境變量,幫助開發者輕松實現多線程并行化。
OpenMP的核心特性包括:
-
基于指令的并行化
通過?#pragma omp
?編譯指導語句實現并行控制,無需手動管理線程。 -
共享內存模型
所有線程共享同一內存空間,可通過共享變量直接通信。 -
工作共享(Work-Sharing)
自動將任務(如循環迭代)分配到多個線程。 -
數據環境管理
明確控制變量的共享(shared
)或私有(private
)屬性。 -
動態線程調度
支持運行時調整線程數量和任務分配策略。
編譯OpenMP支持的FFTW庫
FFTW默認的選項是不編譯OpenMP的,所以想使用OpenMP需要重新編譯一下FFTW庫。
交叉編譯前用如下命令配置:
./configure --prefix=/mnt/d/test/install --host=arm-linux --enable-float --enable-openmp CC=aarch64-linux-gnu-gcc
然后執行make和make install就可以得到相應的頭文件和庫文件。此時庫文件會多一個libfftw3f_omp.a。
?
部署與測試
測試程序
為了使程序支持OpenMP并利用多核系統提升速度,需要進行以下修改:
-
包含OpenMP頭文件:添加
#include <omp.h>
以使用OpenMP函數。 -
初始化FFTW多線程支持:在
main
函數開始時調用fftwf_init_threads()
。 -
設置FFTW使用的線程數:使用
omp_get_max_threads()
獲取可用線程數,并通過fftwf_plan_with_nthreads()
配置。 -
并行化初始化數據的循環(可選):使用
#pragma omp parallel for
加速數據初始化。 -
編譯時鏈接OpenMP和FFTW多線程庫:確保編譯器鏈接
-lfftw3_omp
并添加-fopenmp
選項。
修改后的代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <fftw3.h>
#include <time.h>
#include <omp.h> // 添加OpenMP頭文件// 計算時間差(單位:微秒)
long long get_time_diff_us(struct timespec start, struct timespec end) {return (end.tv_sec - start.tv_sec) * 1000000LL + (end.tv_nsec - start.tv_nsec) / 1000;
}int main() {const int N = 2048;fftwf_complex *in, *out, *back;fftwf_plan p, q;struct timespec start, end;long long fft_time_us, ifft_time_us;// 初始化FFTW多線程支持fftwf_init_threads();int threads = omp_get_max_threads(); // 獲取可用線程數printf("可用線程數 = %d\n", threads);fftwf_plan_with_nthreads(threads); // 設置FFTW使用的線程數// 分配內存in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * N);out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * N);back = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * N);// 并行初始化輸入數據#pragma omp parallel for // 使用OpenMP并行化循環for (int i = 0; i < N; i++) {in[i][0] = (float)i; // 實部in[i][1] = 0.0f; // 虛部}// 創建FFT計劃p = fftwf_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);// 記錄FFT開始時間clock_gettime(CLOCK_MONOTONIC, &start);// 執行FFT(自動多線程加速)fftwf_execute(p);// 記錄FFT結束時間clock_gettime(CLOCK_MONOTONIC, &end);// 計算FFT時間fft_time_us = get_time_diff_us(start, end);// 創建IFFT計劃q = fftwf_plan_dft_1d(N, out, back, FFTW_BACKWARD, FFTW_ESTIMATE);// 記錄IFFT開始時間clock_gettime(CLOCK_MONOTONIC, &start);// 執行IFFT(自動多線程加速)fftwf_execute(q);// 記錄IFFT結束時間clock_gettime(CLOCK_MONOTONIC, &end);// 計算IFFT時間ifft_time_us = get_time_diff_us(start, end);// 輸出結果printf("2048點單精度FFT所需時間: %lld 微秒\n", fft_time_us);printf("2048點單精度IFFT所需時間: %lld 微秒\n", ifft_time_us);// 釋放計劃和內存fftwf_destroy_plan(p);fftwf_destroy_plan(q);fftwf_free(in);fftwf_free(out);fftwf_free(back);return 0;
}
關鍵修改說明:
-
多線程初始化:通過
fftwf_init_threads()
和fftwf_plan_with_nthreads()
啟用FFTW的多線程支持。 -
并行數據初始化:使用OpenMP指令加速數據填充循環(根據實際情況可選)。
-
FFT/IFFT并行計算:FFTW會在執行
fftwf_execute()
時自動使用配置的線程數進行并行計算。
這些修改使得FFT和IFFT計算過程能夠利用多核CPU,從而顯著提升處理速度。
程序編譯的命令行為:
aarch64-linux-gnu-gcc -o fftwtest-openmp fftwtest-openmp.c -Iinclude -Llib -lfftw3f -lm -lfftw3f_omp -fopenmp
程序部署
ELF2開發板默認是沒有OpenMP支持庫的,需要將主機的/usr/aarch64-linux-gnu/lib/libgomp.so.1 拷貝到開發板的/usr/lib目錄下,否則程序運行時會報告錯誤。
測試結果
我本來對程序的運行時間是沒啥期待的,因為2048點對于FFT計算來說太短了,很難并并行加速。結果還行,有些效果,差不多50微秒左右,比NEON加速還快一些。
?RK3588搭載四核A76+四核A55,所以OpenMP可用線程數為8。
結語
OpenMP加速的結果令人欣慰。不過CPU計算FFT可能也就是這個水平了,估計沒法大幅度提升了。?