矩阵/向量操作的GCC优化标志

6
我正在使用C语言执行矩阵运算。我想知道有哪些编译器优化标志可以提高双精度和int64数据的矩阵操作的执行速度,例如乘法、逆等。我不是在寻找手动优化的代码,我只是想使用编译器标志使本地代码更快,并了解这些标志。
到目前为止,我发现可以改善矩阵代码的标志有:
-O3/O4
-funroll-loops
-ffast-math
1个回答

20

首先,出于以下原因,我不建议使用 -ffast-math:

  1. 已经证明,在大多数情况下(如果不是所有情况),使用此选项实际上会导致性能下降。因此,“快速数学”其实并不那么快。

  2. 此选项违反浮点运算的严格IEEE规范,最终会导致计算错误的累积,而这些错误的性质是无法预测的。

  3. 在不同的环境中可能会得到不同的结果,差异可能很大。在这种情况下,“环境”指的是硬件、操作系统和编译器的组合。这意味着可以获得意外结果的情况的多样性呈指数级增长。

  4. 另一个悲惨的后果是:与使用此选项构建的库链接的程序可能期望正确(符合IEEE标准)的浮点数学,但这就是他们的期望破灭的地方,却很难找出原因。

  5. 最后,请查看这篇文章

出于同样的原因,您应避免使用 -Ofast(因为它包括邪恶的 -ffast-math)。摘录如下:

-Ofast

忽略严格的标准合规性。 -Ofast 启用所有 -O3 优化。它还启用了不适用于所有符合标准的程序的优化。它打开了 -ffast-math 和专门针对Fortran的选项 -fno-protect-parens-fstack-arrays

不存在 -O4 这样的标志。至少我不知道这个标志,并且在官方 GCC 文档中也没有找到它的痕迹。所以在这方面的最大值是 -O3,你应该一定要使用它,不仅优化数学,而且在发布构建中普遍使用。

-funroll-loops 是数学例程的一个很好的选择,特别是涉及向量/矩阵操作,其中循环的大小可以在编译时推导出来(结果由编译器展开)。

我可以推荐两个更多的标志:-march=native-mfpmath=sse。类似于 -O3-march=native 对于任何软件的发布构建都是通用的,不仅限于数学密集型。 -mfpmath=sse 启用 XMM 寄存器在浮点指令中的使用(而不是在 x87 模式下的堆栈中)。

此外,我想说的是,很遗憾您不想修改代码以获得更好的性能,因为这是向量/矩阵例程加速的主要来源。由于 SIMDSSE Intrinsics向量化,重型线性代数代码可以比没有它们的代码快几个数量级。然而,正确应用这些技术需要深入了解其内部,并且需要相当多的时间/精力来修改(实际上是重新编写)代码。

不过,在您的情况下,有一种选项可能非常适合。GCC提供自动向量化,可以通过-ftree-vectorize启用,但由于您使用了-O3(因为它已经包含了-ftree-vectorize),所以这是不必要的。重点在于,您仍然应该帮助GCC稍微了解哪些代码可以自动向量化。修改通常很小(如果需要的话),但您必须熟悉它们。因此,请参阅上面链接中的可向量化循环部分。

最后,我建议您研究一下Eigen,这是一个基于C++模板的库,具有大多数常见线性代数例程的高效实现。它非常巧妙地利用了迄今为止介绍的所有技术。接口完全面向对象,整洁且易于使用。面向对象的方法看起来非常相关于线性代数,因为它通常操作诸如矩阵、向量、四元数、旋转、滤波器等纯粹的对象。因此,当使用Eigen编程时,您不必自己处理这些低级概念(如SSE、向量化等),而只需享受解决特定问题的乐趣。


2
我强烈推荐您使用Eigen。它非常容易学习。虽然这篇文章涉及到了许多通常需要考虑的优化方案,但Eigen更进一步,并且执行了许多非常高级的操作。 - Nicu Stiurca
谢谢!这帮了我很多。实际上我正在尝试比较编译器优化代码的最佳加速效果(这是我的问题)与我手动优化矩阵运算的代码。 - laxy
1
@Haroogan:谢谢你的提示。我完全接受你的答案:)。很抱歉我还不能点赞。 - laxy
1
ffast-math导致代码变慢,我认为可以被视为编译器的一个bug,而且是非常令人惊讶的(也许是在没有使用march=native的情况下编译?)。根据我的经验,自动向量化和并行化并不特别有用...即使是最新的ICC(通常是最好的)也会出现简单代码的问题,而且微小的无害更改可能会产生令人惊讶的影响。如果您依赖于性能,请使用编译器内部函数并明确编写。对于Eigen点赞;) - Voo
我在 一个 ICC 帮助主题 中发现了关于 -ffast-math 性能反转的讨论,但是这有点超出了我的理解范围。从 另一个主题 中,我看到“这意味着除非你拥有非常高效的水平向量加法,否则没有可用的矢量化”;在第 5 点中,也许 David 的代码在两种情况下都被矢量化,或者都没有被矢量化,但是值落入某些边缘情况,IEEE 浮点数表现优于实现(通常)快速的浮点表示?(学术上很感兴趣 - 听起来像个头疼的问题。) - John P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接