【发布时间】:2015-10-01 13:19:35
【问题描述】:
我有以下 Fortran 代码
DO ir = 1, N
cfac = exp( ci*B ) / dble( degen(ir) )
C(:,:) = C(:,:) + cfac*D(:,:, ir )
ENDDO
这个循环在 gcc -02 下需要 14.00 秒。
我想优化它。我试过 BLAS 进行矩阵向量乘法的例程:
DO ir = 1, N
cfac(ir) = exp( ci*B ) / dble( degen(ir) )
ENDDO
DO j = 1, M
CALL zgemv ('n', M, N, cone, D(j,:,:), M,cfac(:),1,czero, C(j,:), 1 )
ENDDO
事实证明,我得到了相同的结果,但在 ... 17.67 秒内。
为什么会变慢?如何改进代码(不更改编译器选项)?
谢谢你,
塞缪尔
【问题讨论】:
-
N 和 M 有多大?很可能那些 BLAS 例程根本无法帮助您,而您只是增加了开销。您尝试了哪种 BLAS 实现?编译器很擅长自己优化循环,我不在任何地方使用 GEMV。
-
当您调用 zgemv 时,您也可能会复制输入/复制输出,因为您要在 C 和 D 中访问的元素在内存中不连续。特别是 D 的副本可能会扼杀你的表现。哦,这些是 BLAS 例程 - 这个问题与 ScaLAPACK 无关,而 ScaLAPACK 与 BLAS 非常不同。
-
谢谢伊恩!我已将标题更改为 Blas。您认为可以通过修改代码(使用或不使用 Blas)来提高性能吗?通常 N 很大,而 M 不大。我为这两个循环计时。第一个是 4 秒,第二个是 13.67 秒,结果是 17.67 秒。
-
我不这么认为。但是您仍然没有回复 N 和 M 的值是什么。如果您使用 gfortran,查看
-fdump-tree-optimized的输出会很有用。此外,请尝试-fopt-info以了解编译器进行了哪些优化(例如矢量化)。您可能想尝试 -O2 以不同的方式展开一些循环,它可能会有所帮助,但也会造成伤害。总的来说,我还是很怀疑的,如果编译器已经将它向量化了,那么改进的空间就不大了。 -
另外,不鼓励使用
C(:,:),它可能会混淆优化器,请参阅software.intel.com/en-us/blogs/2008/03/31/…
标签: optimization fortran blas