Performance gfortran“-三月=哈斯韦尔“;慢于-三月=核心2“;

Performance gfortran“-三月=哈斯韦尔“;慢于-三月=核心2“;,performance,gcc,x86,gfortran,Performance,Gcc,X86,Gfortran,我在64位Windows7机器上运行gfortran 4.9.2,该机器采用Intel Core i5-4570(Haswell)。我在同一台机器上编译和执行 使用编译我的代码(科学模拟) 比使用 gfortran -frecord-marker-4 -fno-automatic -O3 -fdefault-real-8 (...) -Wline-truncation -Wsurprising -ffpe-trap=invalid,zero,overflow (...)

我在64位Windows7机器上运行gfortran 4.9.2,该机器采用Intel Core i5-4570(Haswell)。我在同一台机器上编译和执行

使用编译我的代码(科学模拟)

比使用

gfortran -frecord-marker-4 -fno-automatic -O3 -fdefault-real-8 (...)
         -Wline-truncation -Wsurprising -ffpe-trap=invalid,zero,overflow (...)
         -march=haswell -mfpmath=sse -c
-march=native
给出与
-march=haswell
相同的结果)

这让我觉得很奇怪,因为我希望有更多的指令可以让代码更快,而不是更慢

第一:这是一台新机器,是我工作时旧机器的替代品,很不幸:

  • 我无法再使用以前的处理器进行测试
  • 对于我来说,使用另一个gfortran版本进行测试比安装的版本更困难
现在,我使用gprof和不同的
-march=
设置进行了一些评测(请参阅)。在本测试中:

  • core2
    nehalem
    Westmile
    都会导致~85秒
  • sandybridge
    (添加AVX指令集)开始,执行时间跳到122s(对于
    haswell
    ,执行时间跳到128s)
以下是报告的配置文件,在函数>1.0s自时间剪切

-march=core2的平面轮廓:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  us/call  us/call  name    
  8.92      6.18     6.18                             __sinl_internal
  8.50     12.07     5.89                             __cosl_internal
  7.26     17.10     5.03                             _mcount_private
  6.42     21.55     4.45                             exp
  6.41     25.99     4.44                             exp2l
  5.08     29.51     3.52                             __fentry__
  3.71     32.08     2.57 35922427     0.07     0.18  predn_
  3.53     34.53     2.45                             log2l
  3.36     36.86     2.33 79418108     0.03     0.03  vxs_tvxs_
  2.90     38.87     2.01 97875942     0.02     0.02  rk4m_
  2.83     40.83     1.96   403671     4.86    77.44  radarx_
  2.16     42.33     1.50  4063165     0.37     0.43  dchdd_
  2.14     43.81     1.48                             pow
  2.11     45.27     1.46  8475809     0.17     0.27  aerosj_
  2.09     46.72     1.45 23079874     0.06     0.06  snrm2_
  1.86     48.01     1.29                             cos
  1.80     49.26     1.25                             sin
  1.75     50.47     1.21 15980084     0.08     0.08  sgemv_
  1.66     51.62     1.15 61799016     0.02     0.05  x2acc_
  1.64     52.76     1.14 43182542     0.03     0.03  atmostd_
  1.56     53.84     1.08 24821235     0.04     0.04  axb_
  1.53     54.90     1.06 138497449     0.01     0.01  axvc_
-march=haswell的平面剖面图

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  us/call  us/call  name    
  6.49      6.71     6.71                             __sinl_internal
  6.05     12.96     6.25                             __cosl_internal
  5.55     18.70     5.74                             _mcount_private
  5.16     24.03     5.33                             exp
  5.14     29.34     5.31                             cos
  4.87     34.37     5.03                             sin
  4.67     39.20     4.83                             exp2l
  4.55     43.90     4.70 35922756     0.13     0.34  predn_
  4.38     48.43     4.53  8475884     0.53     0.69  aerosj_
  3.72     52.27     3.84                             pow
  3.43     55.82     3.55                             __fentry__
  2.79     58.70     2.88   403672     7.13   120.62  radarx_
  2.64     61.43     2.73 79396558     0.03     0.03  vxs_tvxs_
  2.36     63.87     2.44                             log2l
  1.95     65.89     2.02 97881202     0.02     0.02  rk4m_
  1.80     67.75     1.86 12314052     0.15     0.15  axs_txs_
  1.74     69.55     1.80  8475848     0.21     0.66  mvpd_
  1.72     71.33     1.78 36345392     0.05     0.05  gauss_
  1.53     72.91     1.58 25028687     0.06     0.06  aescudi_
  1.52     74.48     1.57 43187368     0.04     0.04  atmostd_
  1.44     75.97     1.49 23077428     0.06     0.06  snrm2_
  1.43     77.45     1.48 17560212     0.08     0.08  txs_axs_
  1.38     78.88     1.43  4062635     0.35     0.42  dchdd_
  1.36     80.29     1.41                             internal_modf
  1.30     81.63     1.34 61800367     0.02     0.06  x2acc_
  1.26     82.93     1.30                             log
  1.25     84.22     1.29 138497176     0.01     0.01  axvc_
  1.24     85.50     1.28 15978523     0.08     0.08  sgemv_
  1.10     86.64     1.14 10707022     0.11     0.11  ec_txs_
  1.09     87.77     1.13  8475648     0.13     0.21  g_eval_
  1.06     88.87     1.10                             __logl_internal
  0.98     89.88     1.01 17765874     0.06     0.07  solgeo_
  0.98     90.89     1.01 15978523     0.06     0.06  sger_
您会注意到,使用
-haswell
(甚至像sin/cos/exp这样的内部函数!)基本上一切都会变慢

我可以举一个代码示例,函数
vxs\u tvxs
,它消耗2.73s和2.33s:

  SUBROUTINE VXS_TVXS(VXS,TVXS)

  REAL VXS(3),TVXS(3,3)

  VTOT=sqrt(sum(VXS**2))
  VH=sqrt(VXS(1)**2+VXS(2)**2)

  if (VTOT==0.) then
    print*,'PB VXS_TVXS : VTOT=',VTOT
    stop
  endif

  sg=-VXS(3)/VTOT
  cg=VH/VTOT
  if (VH==0.) then
    sc=0.
    cc=1.
  else
    sc=VXS(2)/VH
    cc=VXS(1)/VH
  endif

  TVXS(1,:)=(/ cg*cc, cg*sc, -sg/)
  TVXS(2,:)=(/   -sc,    cc,  0./)
  TVXS(3,:)=(/ sg*cc, sg*sc,  cg/)

  RETURN
  END
对我来说似乎是一个无害的功能

我做了一个非常简单的程序

PROGRAM PIPO
REAL VXS0(3),VXS(3),TVXS(3,3)
VXS0=(/50.,100.,200./)
VXS=VXS0
call cpu_time(start)
do k=1,50 000 000
  call VXS_TVXS(VXS,TVXS)
  VXS=0.5*(VXS0+TVXS(1+mod(k,3),:))
  VXS=cos(VXS)
enddo
call cpu_time(finish)
print*,finish-start,VXS
END
不幸的是,在这个测试用例中,所有的
-march
设置最终都有大约相同的时间要求


所以我真的不明白发生了什么。。。另外,正如我们从前面的简介中看到的,甚至内部功能的成本也越来越高,这一事实让人感到非常困惑。

您能为花费大部分时间的零件分解两个版本并进行后期组装吗<如果使用
-S
选项运行,code>gcc
将保存汇编代码,我不知道
gfortran
是否相同。有很多asm专家经常访问这个网站,如果你能分析你的代码以找到“热点”并将其分解,很有可能有人会为你找到答案。如果只是“这是一个大程序,我不能给出任何细节或显示任何代码”,你就不会得到答案。在这种情况下,你可能会在另一个网站上有更好的运气;这个网站专门用来问一些有明确答案的问题。你使用的是什么版本的gfortran?如果不是最新版本,我建议升级到4.9.2并重试。如果您可以通过评测(通过
-pg
选项和
gprof
)找到一段代码,并且可以显示一段悲观的代码,我建议您将错误报告提交给。通过这种方式,gcc维护人员将了解这个问题,并且它有很好的修复机会(如果是回归,甚至更高,例如,如果相同的选项更早地生成更好的代码)。谢谢harold。我不熟悉如何生成相关的反汇编代码。我知道我应该在编译时使用-S,但是呢?此外,我还将进行一些附加测试,特别是使用非常简单的唯一vxs_tvxs函数。如果我能在一个测试程序上重现相同的行为,即简单地使用不同的值循环vxs_TVX一百万次,那么应该将其缩小到一个gcc/gfortran问题(同时也大大简化了研究,因为要处理的代码只有几行而不是>20k)听起来像是混合了AVX指令(您的程序)和SSE指令(libm),这可能会有很坏的惩罚(可能缺少vzeroupper?)。
PROGRAM PIPO
REAL VXS0(3),VXS(3),TVXS(3,3)
VXS0=(/50.,100.,200./)
VXS=VXS0
call cpu_time(start)
do k=1,50 000 000
  call VXS_TVXS(VXS,TVXS)
  VXS=0.5*(VXS0+TVXS(1+mod(k,3),:))
  VXS=cos(VXS)
enddo
call cpu_time(finish)
print*,finish-start,VXS
END