【问题标题】:Intrinsic dot_product slower than a*a+b*b+c*c?内在 dot_product 比 a*a+b*b+c*c 慢?
【发布时间】: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,808s1,803s。所以实际上两者的速度是一样的。

3。我的实际期望

...是更快的内在函数,因为它可以:

  1. 并行计算 3 个乘积
  2. 添加 3 个产品

显式形式必须按顺序排列:

  1. 计算积1
  2. 计算积2
  3. 计算积3
  4. 添加 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


【解决方案1】:

即使查看未优化的数字也毫无意义。优化后的数字是一样的,所以一切都很好。

“...是更快的内在函数,因为它可以:并行计算 3 个产品”

除非您启用特定的并行优化,否则不会并行执行任何操作。这些优化对于循环和内在循环一样容易,而且对于循环来说通常更容易。

嗯,至少对于使用线程或类似的并行的正常意义。可以并行完成的是使用向量指令并安排指令在 CPU 流水线中重叠。这可以通过优化编译器完成,并且在您使用-O3 时可能对这两个版本都完成。您不应期望在未启用任何优化时会发生这种情况。

有时可以通过使用诸如!$omp simd!$DEC VECTOR 之类的编译器指令来改进“并行”指令 (SIMD) 的使用。

“我是否必须创建一个新的并行 dot_product 函数才能更快?”

是的,通常你会这样做。例如使用 OpenMP。或者你可以:

“或者我不知道 gfortran 编译器还有其他选项吗?”

是的,自动并行化https://gcc.gnu.org/wiki/AutoParInGCC,例如-floop-parallelize-all -ftree-parallelize-loops=4

请注意,它不会使这些单独的乘法并行,它会使i 循环并行。

【讨论】:

    猜你喜欢
    • 2021-10-04
    • 2011-08-01
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    相关资源
    最近更新 更多