Fortran:对代码部分进行计时的最佳方法是什么?

计算科学 优化 正则 分析
2021-11-28 23:51:50

有时在优化代码时需要对代码的某些部分进行计时,多年来我一直在使用以下代码,但想知道是否有更简单/更好的方法来做到这一点?

call system_clock(count_rate=clock_rate) !Find the time rate
call system_clock(count=clock_start)     !Start Timer

call do_something_subroutine             !This is what gets timed

call system_clock(count=clock_stop)      ! Stop Timer

e_time = real(clock_stop-clock_start)/real(clock_rate)
3个回答

还有其他一些方法可以做到这一点,各有优缺点:

  • MPI_WTIME:这是一个高分辨率的挂钟。这可能是最“值得信赖”的选择;它只是工作。不利的一面是,如果您的程序尚未使用 MPI,则必须将 MPI 包装在它周围(这并不难)。
  • 使用 fortran 内在函数(如您所见):这可能是最简单的,通常也足够了,但在奇怪的架构或并行作业上可能效果不佳。关于这个 Stack Overflow有一些讨论
  • 包装 C 调用:Fortran 和 C 是对象兼容的,因此很容易为 C 调用编写包装器。我使用的代码使用 getrusage,这可能是一个奇怪的选择。Stack Overflow 上很多 关于这个的讨论。

我个人的建议是 MPI_WTIME,正如您所知,只要有 MPI,它就会很好地工作。以下是快速搜索的示例

  include 'mpif.h'
  DOUBLE PRECISION :: start, end
  start = MPI_Wtime()

  ! code to be timed

  end   = MPI_Wtime()
  write(*,*) 'That took ',end-start,' seconds'

如果您使用 GNU 编译器,请查看gprof

简而言之,您将在编译器中添加 -g 标志,如下所示:

g77 -g -pg -0 myprogram myprogram.F

然后,运行输出,一个名为 gmon.out 的文件将显示在您的目录中。然后,调用

gprof --line myprogram gmon.out

这将提供逐行的 CPU 时间配置文件。

正如 icurays1 所提到的,分析是最好的。您也可以稍微简化上述...

use utils
...
call tic()
   ! Section to be timed
call toc()
...
call tic()
   ! Section to be timed
call toc()
...

其中 utils 模块包含...

real(8) :: t1,t2
...
subroutine tic()
  implicit none
  call cpu_time(t1)
end subroutine tic

subroutine toc()
  implicit none
  call cpu_time(t2)
  ! if (rank==0) print*,"Time Taken -->", real(t2-t1)
  print*,"Time Taken -->", real(t2-t1)
end subroutine toc

如果您有许多这样的部分,则在 toc 中传递一个字符串,例如“section_id”,以便它打印 id/name 以及时间。