【发布时间】:2018-05-30 15:26:10
【问题描述】:
最近我测试了显式求和和内在函数的运行时差异来计算点积。令人惊讶的是,天真的显式写作更快。
program test
real*8 , dimension(3) :: idmat
real*8 :: dummy(3)
idmat=0
dummy=0
do i=1,3
idmat(i)=1
enddo
do j=1,10**10
! dummy(mod(j,3)+1)=dot_product(idmat,idmat)
dummy(mod(j,3)+1)=idmat(1)*idmat(1)+idmat(2)*idmat(2)+idmat(3)*idmat(3)
enddo
print*, dummy
end program test
这让我感到困惑:
1。无 -O3 优化
如果我使用:gfortran test.f90 -o test ; time ./test
我发现使用函数 dot_product(上面注释)和使用手动显式编写的 4,486s 的运行时间为 6,297s。
这有什么意义?
2。包括-O3优化
如果我使用:gfortran test.f90 -O3 -o test ; time ./test
我发现运行时间分别为 1,808s 和 1,803s。所以实际上两者的速度是一样的。
3。我的实际期望
...是更快的内在函数,因为它可以:
- 并行计算 3 个乘积
- 添加 3 个产品
显式形式必须按顺序排列:
- 计算积1
- 计算积2
- 计算积3
- 添加 3 个产品
我是否必须创建一个新的并行 dot_product 函数才能更快?或者我不知道 gfortran 编译器是否有 additional 选项?
请注意:我在互联网上阅读了有关现代 Fortran 中的 SIMD、自动矢量化和并行化的信息。虽然我学到了一些东西,但我的问题在任何地方都没有得到解答。
【问题讨论】:
-
您没有指定测量“运行时”的方式。你测量包括写和程序启动吗?我认为,一点 O3 编译器会优化 dot_product 出
j循环,也许它甚至足够聪明,可以删除整个循环。在后一种情况下,您几乎只测量写入和程序启动等。 -
@albert 也许我不完全理解你的意思。测量对我来说意味着这个数字:./test 3,27s user 0,00s system 99% cpu 3,286 total
-
这确实是我的意思,你测量的不是点积的时间,而是总的程序执行时间,程序启动和编写语句也是如此。这看起来可能是明智的,但特别是对于这样的小程序并没有提供相关信息。磁盘交互/屏幕交互(写入)也在进行中,这也取决于正在运行的其他进程以及是否可以缓存事物等。我认为当你将循环减少到例如1000 次迭代可能会得到相同的结果。
-
你确定循环执行的次数(见之前的 O3 备注)因为 10**10 大于适合 gfortran 6.4.0 的 32 位整数的数字我得到了 10**10
Error: Arithmetic overflow at (1)并且没有程序。 -
10**9 的时代确实更有意义。但是我尝试过的编译器并没有优化循环。而程序的其他部分则可以忽略不计。
标签: parallel-processing fortran gfortran dot-product