我无法理解的 Fortran 时间问题
A fortran timing issue I cannot understand
我(为理论物理数值方法中的 class)编写了一个非常简单的 2 维随机游走程序。它是:
program random_walk
implicit none
integer, parameter :: Nwalker = 1000000
integer, parameter :: Nstep = 100
integer, parameter :: Nmeas = 10
integer :: posx, posy, move
integer :: is, im, iw
real :: start_time, stop_time
double precision, dimension(Nmeas) :: dist, r2
real :: rnd
do im = 1, Nmeas
dist(im) = im*Nstep
r2(im) = 0.0
end do
call cpu_time(start_time)
do iw = 1, Nwalker
posx = 0
posy = 0
do im = 1, Nmeas
do is = 1, Nstep
call random_number(rnd)
move = 4*rnd
if (move == 0) posx = posx + 1
if (move == 1) posy = posy + 1
if (move == 2) posx = posx - 1
if (move == 3) posy = posy - 1
end do
r2(im) = r2(im) + posx**2 + posy**2
end do
end do
r2 = r2 / Nwalker
call cpu_time(stop_time)
do im = 1, Nmeas
print '(f8.6, " ", f8.6)', log(dist(im)), log(r2(im))
end do
print '("Time = ", f6.3, " seconds")', stop_time - start_time
end program
最后它应该打印 10 行 2 列:第一列是 "time"(步数)的对数,第二列是到原点的平均平方距离的对数。第二列 "on average" 应与第一列相同。到目前为止一切顺利,程序运作良好,结果非常合理。但这里的问题;在我的 macbookpro(2.7 GHz Intel Core i7,编译器 gfortran 7.1.0,优化 -O2)上,平均需要超过 20 秒才能 运行。但是如果我注释掉这些行:
! do im = 1, Nmeas
! print '(f8.6, " ", f8.6)', log(dist(im)), log(r2(im))
! end do
超出了"stop_time"的计算,结果是运行宁时间...不到6秒!?
怎么可能?
这是一个很典型的现象。人们在创建仅测试性能而不会创建有用结果的人工计算时遇到了这个问题。当不打印结果时,编译器可以识别它不需要程序输出的结果,可以完全省略计算。
要检查它,您可以添加 -fdump-tree-optimized
标志以获得称为 GIMPLE 的特殊源代码形式,并且您可以比较这两种源代码变体的输出。它将输出写入名为 yourfilename.f90.something.optimized
的文件。我确实可以看到很大一部分丢失了。基本上整个 r2
数组及其操作都被优化了。如果您更了解,也可以比较生成的程序集。
我(为理论物理数值方法中的 class)编写了一个非常简单的 2 维随机游走程序。它是:
program random_walk
implicit none
integer, parameter :: Nwalker = 1000000
integer, parameter :: Nstep = 100
integer, parameter :: Nmeas = 10
integer :: posx, posy, move
integer :: is, im, iw
real :: start_time, stop_time
double precision, dimension(Nmeas) :: dist, r2
real :: rnd
do im = 1, Nmeas
dist(im) = im*Nstep
r2(im) = 0.0
end do
call cpu_time(start_time)
do iw = 1, Nwalker
posx = 0
posy = 0
do im = 1, Nmeas
do is = 1, Nstep
call random_number(rnd)
move = 4*rnd
if (move == 0) posx = posx + 1
if (move == 1) posy = posy + 1
if (move == 2) posx = posx - 1
if (move == 3) posy = posy - 1
end do
r2(im) = r2(im) + posx**2 + posy**2
end do
end do
r2 = r2 / Nwalker
call cpu_time(stop_time)
do im = 1, Nmeas
print '(f8.6, " ", f8.6)', log(dist(im)), log(r2(im))
end do
print '("Time = ", f6.3, " seconds")', stop_time - start_time
end program
最后它应该打印 10 行 2 列:第一列是 "time"(步数)的对数,第二列是到原点的平均平方距离的对数。第二列 "on average" 应与第一列相同。到目前为止一切顺利,程序运作良好,结果非常合理。但这里的问题;在我的 macbookpro(2.7 GHz Intel Core i7,编译器 gfortran 7.1.0,优化 -O2)上,平均需要超过 20 秒才能 运行。但是如果我注释掉这些行:
! do im = 1, Nmeas
! print '(f8.6, " ", f8.6)', log(dist(im)), log(r2(im))
! end do
超出了"stop_time"的计算,结果是运行宁时间...不到6秒!?
怎么可能?
这是一个很典型的现象。人们在创建仅测试性能而不会创建有用结果的人工计算时遇到了这个问题。当不打印结果时,编译器可以识别它不需要程序输出的结果,可以完全省略计算。
要检查它,您可以添加 -fdump-tree-optimized
标志以获得称为 GIMPLE 的特殊源代码形式,并且您可以比较这两种源代码变体的输出。它将输出写入名为 yourfilename.f90.something.optimized
的文件。我确实可以看到很大一部分丢失了。基本上整个 r2
数组及其操作都被优化了。如果您更了解,也可以比较生成的程序集。