gpt4 book ai didi

c++ - 超出 -O3/-Ofast 的 G++ 优化

转载 作者:IT老高 更新时间:2023-10-28 13:24:18 28 4
gpt4 key购买 nike

问题

我们有一个用于模拟任务的中型程序,我们需要对其进行优化。我们已经尽最大努力将源代码优化到我们编程技能的极限,包括使用 GprofValgrind 进行分析。

最终完成后,我们希望在多个系统上运行该程序可能几个月。因此,我们非常有兴趣将优化推向极限。

所有系统都将在相对较新的硬件(Intel i5 或 i7)上运行 Debian/Linux。

问题

除了 -O3/-Ofast 之外,使用最新版本的 g++ 有哪些可能的优化选项?

我们也对代价高昂的小优化感兴趣,从长远来看,这将带来返回。

我们现在使用的

现在我们使用以下 g++ 优化选项:

  • -Ofast :最高“标准”优化级别。包含的 -ffast-math 没有在我们的计算中造成任何问题,因此我们决定采用它,尽管不符合标准。
  • -march=native :启用所有 CPU 特定指令的使用。
  • -flto 允许跨不同编译单元的链接时间优化。
  • 最佳答案

    大多数答案都提出了替代解决方案,例如不同的编译器或外部库,这很可能会带来大量的重写或集成工作。我将尝试坚持问题所问的问题,并专注于单独使用 GCC 可以完成的工作,根据 OP 的要求,通过激活编译器标志或对代码进行最少的更改。这不是“您必须这样做”的答案,而是更多 GCC 调整的集合,这些调整对我来说效果很好,如果它们与您的特定上下文相关,您可以尝试一下。

    关于原始问题的警告
    在进入细节之前,关于这个问题的一些警告,通常是对于那些会来的人,阅读问题并说“OP 正在优化超出 O3,我应该使用与他相同的标志!”。

  • -march=native 允许使用特定于给定 CPU 架构 的 指令,这些指令不一定在不同的架构上可用。如果在具有不同 CPU 的系统上运行,该程序可能根本无法运行,或者速度明显变慢(因为这也会启用 mtune=native ),因此如果您决定使用它,请注意这一点。更多信息here
  • -Ofast ,如您所说,启用了一些 不符合标准的 优化,因此也应谨慎使用。更多信息here

  • 要试用的其他 GCC 标志
    列出了不同标志的详细信息 here
  • -Ofast 启用 -ffast-math ,进而启用 -fno-math-errno-funsafe-math-optimizations-ffinite-math-only-fno-rounding-math 、 {91046} 和 {91045} 7}您可以通过选择性地添加一些 额外标志 (例如 -fno-signaling-nans-fcx-limited-range 等)来进一步进行 浮点计算优化 。这些不包括在 -fno-signed-zeros 中,可以在计算上提供一些额外的性能提升,但您必须检查它们是否真的对您有益并且不会破坏任何计算。
  • GCC 还具有大量 其他优化标志 ,任何“-O”选项均未启用这些标志。它们被列为“可能会产生损坏代码的实验性选项”,因此再次强调,应谨慎使用它们,并通过测试正确性和基准测试来检查它们的效果。尽管如此,我确实经常使用 -fno-trapping-math ,此选项从未对我产生不需要的结果,并且往往会显着提高性能(即可以在基准测试时进行测量)。不过,这是一种非常依赖于您的处理器的标志类型。 -Ofast 有时也会给出很好的结果(也暗示 -frename-registers ),但这取决于您的实际代码。

  • PGO
    GCC 具有 Profile-Guided Optimisations 功能。没有很多关于它的精确 GCC 文档,但是让它运行非常简单。
  • 首先用 -funroll-loops 编译你的程序。
  • 让程序运行(执行时间会明显变慢,因为代码还将配置文件信息生成到 .gcda 文件中)。
  • 使用 -frename-registers 重新编译程序。如果您的应用程序是多线程的,还要添加 -fprofile-generate 标志。

  • 带有 GCC 的 PGO 可以提供惊人的结果并真正显着提高性能(我看到我最近从事的一个项目的速度提高了 15-20%)。显然,这里的问题是有一些 数据足以代表您的应用程序执行的 ,这些数据并不总是可用或容易获得。
    GCC 的并行模式
    GCC 具有 并行模式 ,该模式在 GCC 4.2 编译器发布时首次发布。
    基本上,它为您提供了 C++ 标准库
    中许多算法的 并行实现。要全局启用它们,您只需向编译器添加 -fprofile-use-fprofile-correction 标志。您还可以在需要时有选择地启用每个算法,但这将需要一些小的代码更改。
    有关此并行模式的所有信息都可以在 here 中找到。
    如果您经常在大型数据结构上使用这些算法,并且有许多可用的硬件线程上下文,那么这些并行实现可以带来巨大的性能提升。到目前为止,我只使用了 -fopenmp 的并行实现,但为了给出一个粗略的想法,我设法将我的一个应用程序中的排序时间从 14 秒减少到 4 秒(测试环境:包含 1 亿个对象的 vector )自定义比较器功能和 8 核机器)。
    额外的技巧
    与前面的要点部分不同,这部分 需要对代码 进行一些小的更改。它们也是特定于 GCC 的(其中一些也适用于 Clang),因此应使用编译时宏来保持代码在其他编译器上的可移植性。本节包含一些更高级的技术,如果您对正在发生的事情没有一些汇编级别的理解,则不应使用。另请注意,现在处理器和编译器非常智能,因此从这里描述的函数中获得任何明显的好处可能很棘手。
  • GCC 内置函数,列在 here 中。 -D_GLIBCXX_PARALLEL 等结构可以通过向编译器提供 分支预测 信息来帮助编译器进行更好的优化。其他构造(例如 sort)在数据被访问之前将数据带入缓存,有助于减少 缓存未命中
  • 函数属性,列在 here 中。特别是,您应该查看 __builtin_expect__builtin_prefetch 属性;前者会向编译器表明该函数是程序的热点,并更加积极地优化该函数并将其放置在文本段的特殊子段中,以获得更好的局部性;后者将优化函数的大小并将其放置在文本部分的另一个特殊子部分中。

  • 我希望这个答案对一些开发人员有用,我很乐意考虑任何编辑或建议。

    关于c++ - 超出 -O3/-Ofast 的 G++ 优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14492436/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com