6

我正在使用 C 执行矩阵运算。我想知道各种编译器优化标志是什么,以提高双精度和 int64 数据的这些矩阵运算的执行速度 - 例如乘法、逆运算等。我不是在寻找手动优化的代码,我只是想使用编译器标志使本机代码更快,并了解有关这些标志的更多信息。

到目前为止我发现的改进矩阵代码的标志。

-O3/O4
-funroll-loops
-ffast-math
4

1 回答 1

19

首先,我不推荐使用-ffast-math,原因如下:

  1. 事实证明,在大多数(如果不是全部)情况下使用此选项时性能实际上会降低。所以“快速数学”实际上并没有那么快。

  2. 此选项违反了对浮点运算的严格 IEEE 合规性,最终导致不可预测性质的计算错误的累积。

  3. 在不同的环境中,您很可能会得到不同的结果,并且差异可能很大。术语环境(在这种情况下)意味着以下组合:硬件、操作系统、编译器。这意味着当您获得意想不到的结果时,情况的多样性呈指数级增长。

  4. 另一个可悲的结果是,链接到使用此选项构建的库的程序可能期望正确的(符合 IEEE 的)浮点数学,这就是他们的期望中断的地方,但很难弄清楚原因。

  5. 最后,看看这篇文章

出于同样的原因,您应该避免-Ofast(因为它包括 evil -ffast-math)。提炼:

-Ofast

无视严格的标准合规性。-Ofast启用所有-O3优化。它还支持并非对所有符合标准的程序都有效的优化。它打开-ffast-math和特定于 Fortran 的-fno-protect-parens-fstack-arrays.

没有这样的标志-O4。至少我不知道那个,在官方的 GCC 文档中也没有它的踪迹。所以这方面的最大值是-O3,你绝对应该使用它,不仅是为了优化数学,而且是在一般的发布版本中。

-funroll-loops对于数学例程来说是一个非常好的选择,尤其是涉及到向量/矩阵运算,其中循环的大小可以在编译时推断(并因此由编译器展开)。

我可以再推荐 2 个标志:-march=native-mfpmath=sse. 与 类似-O3-march=native通常适用于任何软件的发布版本,而不仅仅是数学密集型。-mfpmath=sse允许在浮点指令中使用 XMM 寄存器(而不是x87 模式中的堆栈)。

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

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

最后,我建议您研究Eigen,这是一个基于 C++ 模板的库,它可以高效地实现大多数常见的线性代数例程。它以一种非常聪明的方式利用了到目前为止这里提到的所有技术。该界面纯粹是面向对象的,整洁且易于使用。面向对象的方法看起来与线性代数非常相关,因为它通常处理诸如矩阵、向量、四元数、旋转、过滤器等纯对象。因此,在使用 Eigen 编程时,您不必自己处理这些低级概念(如 SSE、矢量化等),而只需享受解决您的特定问题的乐趣。

于 2013-04-17T20:41:03.097 回答