Fortran中DO CONCURRENT代码性能评估及异常结果咨询
Fortran DO CONCURRENT 性能疑问解答
背景与测试环境
我正在探索Fortran的新特性,重点研究DO CONCURRENT——该特性据称可通过更简洁的指令达到与OpenACC相当的速度。测试环境为Windows10的WSL虚拟机,使用最新版NVIDIA编译器,编译命令如下:
nvfortran -stdpar=multicore -Minfo=accel myModule.F90 main.F90
测试目的是对比DO CONCURRENT与串行版本的性能提升。
测试代码
主程序代码
1 PROGRAM main 2 USE myModule_m 3 IMPLICIT NONE 4 5 !> declare some variables 6 INTEGER, PARAMETER :: N = 500000000 7 REAL(KIND=wp), DIMENSION(N) :: testArray 8 INTEGER :: i 9 REAL(KIND=wp) :: T1,T2,T3,T4 10 11 ! initial condition 12 testArray = 0.0_wp 13 14 T1 = wtime() 15 ! test the main loop in serial 16 DO i = 1,N 17 testArray(i) = testArray(i) + 1.0_wp 18 END DO 19 T2 = wtime() 20 21 WRITE(*,*) 'Serial time is = ',T2-T1 22 23 ! reset initial condition 24 testArray = 0.0_wp 25 26 T3 = wtime() 27 !! test the main loop in parallel 28 DO CONCURRENT (i=1:N) 29 testArray(i) = testArray(i) + 2.0_wp 30 END DO 31 T4 = wtime() 32 33 WRITE(*,*) 'Multi-threaded time is = ',T4-T3 34 WRITE(*,*) 'Result = ',SUM(testArray) 35 STOP 36 END PROGRAM main
模块代码
1 MODULE myModule_m 2 IMPLICIT NONE 3 4 INTEGER, PARAMETER :: wp = KIND(1.0D0) 5 CONTAINS 6 7 FUNCTION wtime() RESULT(time) 8 IMPLICIT NONE 9 10 !> local variables 11 INTEGER :: clock_max, clock_rate, clock_reading 12 REAL(KIND=wp) :: time 13 14 CALL SYSTEM_CLOCK(clock_reading, clock_rate, clock_max) 15 16 time = REAL(clock_reading,KIND=wp)/REAL(clock_rate,kind=wp) 17 END FUNCTION wtime 18 19 END MODULE myModule_m
测试现象
- 未加
-stdpar=multicore编译时,DO CONCURRENT与串行版本耗时相当; - 启用该标志后,小数据量下DO CONCURRENT耗时更长,仅在超大数组时性能才接近串行。
疑问解答:这是正常现象
出现上述情况并非操作错误,而是由并行化的固有特性和测试任务类型决定的,具体原因如下:
1. 并行化固定开销不可忽视
启用-stdpar=multicore后,编译器会为DO CONCURRENT生成多线程代码,但线程创建、任务调度、数据分片等操作存在固定开销。当数据量较小时,这些开销会完全覆盖并行计算带来的收益,导致总耗时高于串行版本。只有当数据量足够大,并行计算的收益超过开销时,才能体现出优势。
2. 测试任务属于内存绑定型
你的测试代码是简单的数组元素自增操作,这类任务的性能瓶颈是内存带宽,而非CPU计算能力。即使并行化,也无法突破硬件的内存带宽上限——串行版本的循环可能已经被编译器做了向量化等极致优化,充分利用了内存带宽,因此并行版本的性能很难超越串行版本,只能接近。
3. 串行版本的编译器优化更充分
串行循环的依赖关系简单,编译器可以进行更激进的优化(比如循环展开、向量化、寄存器重用等);而并行版本为了保证线程安全,部分优化会被限制,进一步缩小了与串行版本的性能差距。
优化建议
- 改用计算密集型任务(如复杂浮点运算、矩阵乘法等)测试并行加速效果,这类任务能更好地发挥多线程的优势;
- 设置环境变量
OMP_NUM_THREADS控制线程数(NVIDIA stdpar底层通常基于OpenMP实现),确保线程数与CPU核心数匹配,避免过度调度; - 查看
-Minfo=accel的输出,确认编译器是否成功将DO CONCURRENT并行化(若输出无类似DO CONCURRENT transformed to parallel loop的提示,需检查编译选项或循环并行性)。
内容的提问来源于stack exchange,提问作者Principio Tudisco
相关产品推荐
相关产品推荐

