Ubuntu 下 Fortran 性能测试与分析方法
一 环境准备与基线测试
- 安装工具链:sudo apt update && sudo apt install gfortran linux-tools-common linux-tools-generic linux-tools-$(uname -r)。基线测试建议使用 CPU 时间测量与系统级统计两种方式交叉验证。示例程序使用 cpu_time 获取壁钟时间,编译开启 -O3 作为优化基线;同时可用 perf stat 获取指令级与缓存相关事件,形成可重复的基线报告。
program main
implicit none
real :: t0, t1, elapsed
call cpu_time(t0)
call workload()
call cpu_time(t1)
elapsed = t1 - t0
print '("Elapsed CPU time: ", F0.4, " s")', elapsed
contains
subroutine workload()
implicit none
integer, parameter :: n = 100_000_000
real :: s, x
integer :: i
s = 0.0
do i = 1, n
x = real(i)
s = s + x * x
end do
end subroutine workload
end program main
- 编译与运行:
- gfortran -O3 -o main main.f90 && ./main
- perf stat -e instructions,cpu-cycles,cache-misses,cache-references,branch-misses,cpu-clock ./main
- 建议固定 CPU 亲和性(如 taskset)、关闭省电/超线程干扰、预热后再计时,减少噪声。
二 编译器与数学库优化对比
- 优化级别对比:在相同代码与数据规模下,依次测试 -O2、-O3、必要时配合 -march=native 以启用本地指令集;记录每次的 CPU 时间与 perf 指标,观察是否出现向量化与指令级改进。
- 数学库对比:对矩阵/向量密集运算,链接优化版 BLAS/LAPACK(如 OpenBLAS、Intel MKL),对比纯 Fortran 实现与库实现的性能差异;编译示例:gfortran -O3 -march=native myblas.f90 -lopenblas -llapack。
- 并行化对比:在循环或区域前后加入 OpenMP 指令,编译时启用 -fopenmp,并使用 OMP_NUM_THREADS 控制线程数;对比 1、2、4、8… 线程的强/弱扩展效率与 perf 的 CPU 利用率。
三 采样与热点定位
- gprof 函数级热点:编译时加入 -pg,运行生成 gmon.out,再用 gprof 生成报告。示例:gfortran -O3 -pg -o main main.f90 && ./main && gprof main gmon.out > gprof.txt。适合定位占时比例较高的子程序与调用关系。
- perf + FlameGraph 火焰图:编译时加入 -g 保留调试信息,使用 perf record -e cpu-clock -g ./main 采集调用栈,随后用 FlameGraph 生成 SVG 火焰图直观查看热点路径与调用占比。
- 内存与堆分析:使用 Valgrind 的 Massif 观察堆内存分配随时间的变化,定位大对象分配与潜在泄漏;命令示例:valgrind --tool=massif ./main,再用 ms_print 查看报告。
四 结果判读与可重复实验
- 指标口径统一:优先采用可重复的 CPU 时间(如示例中的 cpu_time),并用 perf stat 报告硬件事件(如指令数、缓存命中/未命中、分支预测失败)作为补充;系统负载、CPU 频率策略、NUMA 绑定都会影响结果,需在报告中记录环境信息。
- 重复与统计:同一配置建议运行 ≥3–5 次,剔除异常点后取均值与标准差;对比不同优化/并行配置时,保持输入规模与随机种子一致,确保可比性。
- 判定依据:若优化后 CPU 时间显著下降、指令数减少或缓存命中率提升,且火焰图热点迁移到更期望的例程,通常可判定为有效优化;若性能波动较大,应检查功耗/频率策略、线程绑定、内存带宽与 I/O 干扰等因素。