内在 dot_product 比 a*a+b*b+c*c 慢?

Intrinsic dot_product slower than a*a+b*b+c*c?

最近我测试了显式求和和内函数计算点积的运行时差异。令人惊讶的是,天真的 显式写入速度更快

  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、自动矢量化和并行化的信息。虽然我学到了一些东西,但我的问题在任何地方都没有得到解答。

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

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

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

好吧,至少对于 parallel 使用线程或类似的正常意义上来说是这样。可以并行完成的是使用矢量指令并安排指令在 CPU 流水线中重叠。这可以通过优化编译器来完成,并且在您使用 -O3 时可能对两个版本都完成。当没有启用优化时,您不应该期望发生这种情况。

“并行”指令 (SIMD) 的使用有时可以通过使用 !$omp simd!$DEC VECTOR 等编译器指令得到改进。

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

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

“或者 gfortran 编译器是否有我不知道的附加选项?”

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

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