【问题标题】:Why is matmul slower with gfortran compiler optimization turned on?为什么打开 gfortran 编译器优化后 matmul 会变慢?
【发布时间】:2021-03-17 22:30:10
【问题描述】:

如果我在我的 Mac 上使用 gfortran (Homebrew GCC 8.2.0) 编译下面的简单程序而不进行优化 (-O0),则对 matmul 的调用始终在 ~90 毫秒内执行。如果我使用任何优化(标志-O1-O2-O3),执行时间会增加到~250 毫秒。我尝试为inVectmatrix 使用各种不同的大小,但在所有情况下,-O0 选项的性能都优于其他三个优化标志至少 2.5 倍。如果我使用只有几百个元素的较小矩阵,但循环多次调用 matmul,性能损失会更糟,接近 10 倍。

有没有办法避免这种行为?我需要在代码的某些部分使用优化,但同时,我也希望尽可能高效地执行矩阵乘法。

我使用命令gfortran -ON sandbox.f90 编译包含以下代码的文件sandbox.f90,其中N 是优化级别0-3(不使用其他编译器标志)。打印outVect 的第一个值只是为了防止gfortran 优化变得聪明而完全跳过对matmul 的调用。

我是 Fortran 新手,所以如果我在这里遗漏了一些明显的东西,我提前道歉。

program main
implicit none
    real :: inVect(20000), matrix(20000,10000), outVect(10000)
    real :: start, finish

    call random_number(inVect)
    call random_number(matrix)
        
    call cpu_time(start)
    outVect = matmul(inVect, matrix)
    call cpu_time(finish)

    print '("Time = ",f10.7," seconds. – First Value = ",f10.4)',finish-start,outVect(1)
end program main

【问题讨论】:

  • 我看不出-O0 会更快的原因。但是,您可以尝试使用 BLAS 进行矩阵向量乘法并检查其执行方式(sgemvdgemv 应该为您完成)。要了解幕后发生的事情,您可以尝试汇编输出 (gfortran -S -o sandbox.asm sandbox.f90 -ON) 并比较它们。
  • 很奇怪。此计算应主要受您的内存带宽限制。你用的是M1处理器吗?虚拟机?
  • 简单的答案是 gfortran 被 MATMUL(以及可能的其他内在过程)严重破坏,因为它的前端优化通过。我不会向你提供细节。您需要提交错误报告。
  • @steve 我不认为 gfortran 与 MATMUL 或其他内在过程都没有那么糟糕。据我所知,gfortran 是一款非常出色的产品。然而,由于它接近机器硬件(与其他语言相比),有时给定行为背后的原因并非微不足道。
  • @JérômeRichard 我在 2017 MacBook Air(1.8 GHz 双核 Intel Core i5;8 GB 1600 MHz DDR3;macOS Catalina)上使用了相当基本的设置(无 VM)。

标签: optimization fortran matrix-multiplication gfortran


【解决方案1】:

首先,考虑一下我可能是错的。第一次看到这个问题,和你一样惊讶。

我刚刚研究了这个问题,我的理解如下。优化-O0O3Ofast 和...是针对大多数一般(常见)情况编写的。然而,在某些情况下(当-O3 的效率低于-O*<-O3 时),优化会带来一个缺点。这是因为这些优化会隐式调用导致特定任务执行时间较短的标志。对于您的情况,-O3 强制要求所有matmul() 函数都将被内联。这样的事情通常是好的,但对于大数组或此函数的多次调用来说不是必需的。不知何故,内联matmul() 的成本比内联函数获得的收益更重要(至少我是这么看的)。

为了避免这种行为,我建议使用标志-O3 -finline-matmul-limit=0 取消matmul 函数的内联。使用标志-O3 -finline-matmul-limit=0 导致执行时间不比-O0 获得的最差。

您可以使用-finline-matmul-limit=n,仅当涉及的数组小于n 时,您将内联matmul 函数。为简单起见,我使用n=0

希望对你有所帮助。

【讨论】:

  • -finline-matmul-limit=0 标志似乎解决了我测试过的所有情况下的问题,包括循环多次调用 matmul 导致最大速度减慢的情况。内联如何在如此简单的程序中产生 10 倍的速度对我来说完全是个谜,但我很高兴有一个解决方案。谢谢!
  • 老实说,我也是。但是,我没有更好的解释。
  • 这个问题只影响向量矩阵乘法。正在准备修复。在此类事件中,谨慎的做法是直接联系 gfortran 开发人员,而不是希望有人为您做这件事。 GCC gfortran list.
  • @steve 感谢您将该帖子添加到留言板。老实说,我不完全确定这个问题不是用户错误(正如我所说,我是 Fortran 新手)所以我决定先在这里发布。今后,我会直接与开发人员联系。
猜你喜欢
  • 2011-10-22
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 2020-07-24
  • 2017-11-06
  • 2015-09-15
  • 1970-01-01
相关资源
最近更新 更多