内在 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,808s 和 1,803s。所以两者实际上是相同的速度。
3。我的实际期望
...是更快的内在函数,因为它可以:
- 并行计算 3 个产品
- 添加 3 个产品
显式形式必须按顺序:
- 计算产品 1
- 计算产品 2
- 计算产品 3
- 添加 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
循环并行进行。
最近我测试了显式求和和内函数计算点积的运行时差异。令人惊讶的是,天真的 显式写入速度更快 。
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、自动矢量化和并行化的信息。虽然我学到了一些东西,但我的问题在任何地方都没有得到解答。
即使查看未优化的数字也没有任何意义。优化后的数字是一样的,所以一切都很好。
"...是更快的内在函数,因为它可以:并行计算 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
循环并行进行。