为啥优化标志 (-O3) 不能加快四倍精度计算?

Posted

技术标签:

【中文标题】为啥优化标志 (-O3) 不能加快四倍精度计算?【英文标题】:Why optimization flag (-O3) doesn't speed up quadruple precision calculations?为什么优化标志 (-O3) 不能加快四倍精度计算? 【发布时间】:2015-06-26 07:34:40 【问题描述】:

我有一个用 C++ 编写的高精度 ODE(常微分方程)求解器。我使用用户定义类型real_type 进行所有计算。在 header 中有一个 typedef 声明了这个类型:

typedef long double real_type;

我决定将 long double 类型更改为 __float128 以提高准确性。除此之外,我还包含了quadmath.h,并将所有标准数学函数替换为来自 libquadmath 的函数。

如果“long double”版本是在没有任何优化标志的情况下构建的,一些参考 ODE 会在 77 秒内解决。如果这个版本是用 -O3 标志构建的,同样的 ODE 会在 25 秒内解决。因此 -O3 标志将计算速度提高了三倍。

但是在没有标志的“__float 128”版本中,类似的 ODE 可以在 190 秒内解决,而使用 -O3 则需要 160 秒(大约 15% 的差异)。为什么 -O3 优化对四倍精度计算的影响如此微弱?也许我应该使用其他编译器标志或包含其他库?

【问题讨论】:

我将此作为评论而不是作为答案发布,因为它只是一个“知情猜测”:编译器优化标志启用/禁用某些优化。根据您的程序、数据和控制流、使用的数据类型……不同的优化会产生不同的效果。因此,仅仅因为使用一种数据类型可以通过 -O3 获得良好的加速,并不意味着在替换数据类型或执行任何其他更改时可以获得相同的加速。所以在我看来,没有理由期待同样的加速。 __float128 操作已经在库中编译(优化),它们不会为每个应用程序重新编译。可能发生这种情况的唯一方法是使用 -flto 编译 libquadmath,这并不容易,而且您可能不会获得太多收益。 感谢您的回复。您认为达到了限速还是我可以加快速度? 如果您想要更高的精度但仍然需要高性能,double-double arithmetic(甚至是三倍、四倍......)可能是一个不错的选择,因为它可以在硬件而不是软件中完成像四重算术。 ***.com/q/9857418/995714***.com/q/6769881/995714 【参考方案1】:

编译器优化的工作方式如下:编译器识别代码中的某些模式,并用等效但更快的版本替换它们。在不确切知道您的代码是什么样子以及编译器执行了哪些优化的情况下,我们无法说出编译器缺少什么。

编译器可能知道如何对本机浮点类型及其操作执行一些优化,但它不知道在 __float128 和操作的库实现上执行。它可能无法识别这些操作的本质。也许它无法查看库实现(您应该尝试将库与您的程序一起编译并启用链接时优化)。

【讨论】:

【参考方案2】:

相同的优化提供了基本相同的好处。百分比下降只是因为数学本身花费的时间更长。

要相信优化应该是相同的百分比,您必须相信使数学运算时间更长会以某种方式使优化器找到更多节省。为什么会这样想?

【讨论】:

【参考方案3】:

如果您的目标是 x86 架构,那么在 GCC 中,__float128 是实际的四倍精度 FP 类型,而 long double 是 x87 96 位 FP 类型(双扩展)。

具有较小精度类型的数学可以比具有较大精度类型的数学更快是合理的。使用本机硬件类型的数学可以比使用非本机类型的数学更快也是合理的。

【讨论】:

以上是关于为啥优化标志 (-O3) 不能加快四倍精度计算?的主要内容,如果未能解决你的问题,请参考以下文章

带有 nojvm 或优化标志的 mcc -B 选项

C++ (GCC) 中的四倍精度

为啥 -O3 GCC Optimization 没有内联这个函数?

使用 -O3 的冒泡排序比使用 GCC 的 -O2 慢

使用 CMake 编译 openCV:设置架构和优化标志

Emacs 23 使用的字符集是 Unicode 的四倍——为啥?