Fortran90中循环内操作数翻倍但CPU耗时未翻倍的原因咨询
Fortran90中循环内操作数翻倍但CPU耗时未翻倍的原因咨询
嗨,我来帮你捋捋这个问题~首先先把你的测试代码和输出整理出来,方便一起分析:
你的测试代码
program test integer :: i, n real :: time_begin, time_end real, dimension(50000000) :: x, y, z, a, b n = 50000000 do i = 1, n x(i) = real( i) y(i) = real(2*i) z(i) = real(3*i) end do a = 0.0 call cpu_time( time_begin ) do i = 1, n a(i) = a(i) + ( x(i) + z(i) ) end do call cpu_time( time_end ) write(*,*) " time1 = ", time_end - time_begin a = 0.0 b = 0.0 call cpu_time( time_begin ) do i = 1, n a(i) = a(i) + ( x(i) + z(i) ) b(i) = b(i) + ( y(i) + z(i) ) end do call cpu_time( time_end ) write(*,*) " time2 = ", time_end - time_begin end program test
你的测试输出
time1 = 0.158164978
time2 = 0.230790973
接下来聊聊为什么time2没有达到time1的两倍,主要有几个核心原因:
CPU的超标量执行与流水线优化:现代CPU都是超标量设计,能同时并行执行多条指令,还拥有长流水线提升吞吐量。第一个循环里,CPU的执行单元可能还有空闲;第二个循环新增的
b(i)相关操作刚好能填满这些空闲单元,所以不需要额外付出两倍的时间成本。编译器的向量化优化:Fortran编译器(比如gfortran、ifort)默认会对这种规整的数组循环做向量化优化——简单说就是把多个数组元素的操作打包成一条SIMD指令(比如AVX、SSE)一次性处理。第一个循环里,一条SIMD指令处理一组
x(i)+z(i)并赋值给a(i);第二个循环里,编译器可以把a和b的操作合并到同一条或相邻的SIMD指令里,整体开销不会线性翻倍。内存带宽与缓存利用率:你的数组都是连续的大数组,第一次循环后,
x、z这些数据已经被加载到CPU高速缓存中。第二个循环里,y、z的缓存命中率也很高,不需要频繁从慢速的主内存读取数据——内存访问是耗时的瓶颈操作,而缓存访问速度快得多,所以新增的操作不会因为内存瓶颈导致耗时翻倍。
简单总结就是,现代CPU的硬件特性加上Fortran编译器的针对性优化,让代码的执行效率远超“操作数翻倍耗时翻倍”的理想情况,这也是Fortran适合科学计算的重要原因之一~
备注:内容来源于stack exchange,提问作者cfd39
相关产品推荐
相关产品推荐

