【问题标题】:Fortran intrinsic timing routines, which is better? cpu_time or system_clockFortran 内在计时例程,哪个更好? cpu_time 或 system_clock
【发布时间】:2011-07-29 19:44:50
【问题描述】:

在为 FORTRAN 程序计时时,我通常只使用命令 call cpu_time(t)
然后我偶然发现了call system_clock([count,count_rate,count_max]),它似乎做同样的事情。然而,在一个更困难的庄园。 我对这些的了解来自:Old Intel documentation.
我无法在英特尔的主页上找到它。请参阅下面的标记。

  1. 哪个更准确,或者它们相似?
  2. 其中一个是否计算缓存未命中(或其他类型)而另一个不计算,或者其中任何一个?
  3. 或者唯一的区别是我在下面的标记中标记的东西?

这些是我的问题,下面我提供了一个代码供您查看一些时间和用法。他们向我展示了它们在输出上非常相似,因此在实现上似乎也很相似。
我应该注意,我可能会一直坚持使用cpu_time,而且我真的不需要更精确的时间安排。

在下面的代码中,我尝试比较它们。 (我也尝试过更复杂的东西,但为了保持简洁,不会提供) 所以基本上我的结果是:

  • cpu_time
    1. 更容易使用,不需要初始化调用
    2. 直接时间差
    3. 也应该是特定于编译器的,但无法查看精度。 (标准是毫秒)
    4. 是线程时间的总和。 IE。不建议用于并行运行。
  • system_clock
    1. 需要预初始化。
    2. 后处理,以分割的形式。 (小事,但还是有区别的)
    3. 是特定于编译器的。在我的电脑上发现了以下内容:
      • Intel 12.0.4 由于 INTEGER 精度,使用计数率为 10000。
      • gcc-4.4.5使用1000,不知道如何区分
    4. 容易遇到环绕,即如果c1 > c2,由于count_max
    5. 是一个标准时间的时间。因此,这将产生一个线程的实际时间,而不是总和。

代码:

PROGRAM timer
  IMPLICIT NONE
  REAL :: t1,t2,rate 
  INTEGER :: c1,c2,cr,cm,i,j,n,s
  INTEGER , PARAMETER :: x=20000,y=15000,runs=1000
  REAL :: array(x,y),a_diff,diff

  ! First initialize the system_clock
  CALL system_clock(count_rate=cr)
  CALL system_clock(count_max=cm)
  rate = REAL(cr)
  WRITE(*,*) "system_clock rate ",rate

  diff = 0.0
  a_diff = 0.0
  s = 0
  DO n = 1 , runs
     CALL CPU_TIME(t1)
     CALL SYSTEM_CLOCK(c1)
     FORALL(i = 1:x,j = 1:y)
        array(i,j) = REAL(i)*REAL(j) + 2
     END FORALL
     CALL CPU_TIME(t2)
     CALL SYSTEM_CLOCK(c2)
     array(1,1) = array(1,2)     
     IF ( (c2 - c1)/rate < (t2-t1) ) s = s + 1
     diff = (c2 - c1)/rate - (t2-t1) + diff
     a_diff = ABS((c2 - c1)/rate - (t2-t1)) + a_diff
  END DO

  WRITE(*,*) "system_clock : ",(c2 - c1)/rate
  WRITE(*,*) "cpu_time     : ",(t2-t1)
  WRITE(*,*) "sc < ct      : ",s,"of",runs
  WRITE(*,*) "mean diff    : ",diff/runs
  WRITE(*,*) "abs mean diff: ",a_diff/runs
END PROGRAM timer

为了完成,我在这里给出我的 Intel 12.0.4 和 gcc-4.4.5 编译器的输出。

  • Intel 12.0.4-O0

    system_clock rate    10000.00    
    system_clock :    2.389600    
    cpu_time     :    2.384033    
    sc < ct      :            1 of        1000
    mean diff    :   4.2409324E-03
    abs mean diff:   4.2409897E-03
    
    real    42m5.340s
    user    41m48.869s
    sys 0m12.233s
    
  • gcc-4.4.5-O0

    system_clock rate    1000.0000    
    system_clock :    1.1849999    
    cpu_time     :    1.1840820    
    sc < ct      :          275 of        1000  
    mean diff    :   2.05709646E-03  
    abs mean diff:   2.71424348E-03  
    
    real    19m45.351s  
    user    19m42.954s  
    sys 0m0.348s  
    

感谢阅读...

【问题讨论】:

  • 在gfortran中使用INTEGER(8)作为SYSTEM_CLOCK会显着增加count_max,对于其他一些编译器也应该是这样。

标签: timer fortran


【解决方案1】:

这两个内在函数报告不同类型的时间。 system_clock 报告“墙上时间”或经过的时间。 cpu_time 报告 CPU 使用的时间。在多任务机器上,这些可能会非常不同,例如,如果您的进程与其他三个进程平均共享 CPU,因此获得了 25% 的 CPU 并使用了 10 个 cpu 秒,那么实际经过或墙壁大约需要 40 秒时钟时间。

【讨论】:

  • 正如我在我的问题中所写的,这也是我认为的主要区别。但还有其他更微妙的吗?
【解决方案2】:

cpu_time() 在 Intel 兼容 CPU 上的分辨率通常约为 0.01 秒。这意味着较小的时间间隔可能算作零时间。 大多数当前的 linux 编译器使 system_clock() 的分辨率取决于参数的数据类型,因此 integer(int64) 将提供优于 1 微秒的分辨率,并允许在很长的时间间隔内进行计数。 用于 Windows 的 gfortran 最近(在 2015 年期间)进行了更改,以使 system_clock() 等效于 query_performance 调用。然而,即使在 omp_get_wtime 更改为使用 query_performance 之后,ifort Windows 仍然显示 system_clock 的分辨率约为 0.01。 我会打折以前的 cmets 以时钟滴答为单位测量 cpu_time 或 system_clock 分辨率,特别是如果这可能被认为与 CPU 或数据总线滴答有关,例如 rdtsc 指令可以报告。

【讨论】:

    【解决方案3】:

    我发现itime(请参阅gfortran manual)是system_clock 的一个很好的替代方案,用于为fortran 程序计时。它非常易于使用:

    integer, dimension(3) :: time
    call itime(time)
    print *, 'Hour:  ', time(1)
    print *, 'Minute:', time(2)
    print *, 'Second:', time(3)
    

    【讨论】:

    • 问题是它是一个非标准的扩展。
    • 它可能是非标准的(GNU 扩展),但它被许多编译器支持。我测试并发现它可以与 ifort、pgf90、sunf90 和 g95 一起使用。
    • 这不会改变任何事情。另外,这个问题根本不是问的。
    • 这是一个有效的观点。在评论中提及itime 可能比在答案中更好。
    【解决方案4】:

    我发现 secnds() 是获得挂壁时间的最简单方法。它的用法几乎与 cpu_time() 相同。

    real(8)::t1,delta
    t1=secnds(0.0)
    !Do stuff
    delta=seconds(t1)
    

    【讨论】:

    • 这是所有编译器的内在函数吗?那么这与其他的相比有什么不同呢?
    • 它似乎不是 gfortran 的内在函数
    • 我现在使用system_clock
    猜你喜欢
    • 1970-01-01
    • 2010-11-15
    • 2015-05-14
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    • 2011-02-22
    • 2013-06-06
    • 2013-11-02
    相关资源
    最近更新 更多