【问题标题】:GCC standard optimizations behaviorGCC 标准优化行为
【发布时间】:2016-02-23 07:31:33
【问题描述】:

这里我编译了一个 -O2 优化级别的输入程序(使用 gcc 4.8.4)并测量执行时间:

gcc -O2 -c test.c -o obj.o
TIMEFORMAT='%3R' &&  time(./obj.o)
execution time = 1.825

当我用 -O2 https://gcc.gnu.org/onlinedocs/gcc-4.8.4/gcc/Optimize-Options.html#Optimize-Options 级别的 GCC 手册中定义的选项列表替换 -O2 标志时:

gcc -fauto-inc-dec -fcompare-elim -fcprop-registers -fdce -fdefer-pop -fdse -fguess-branch-probability -fif-conversion2 -fif-conversion -fipa-pure-const -fipa-profile -fipa-reference -fmerge-constants -fsplit-wide-types -ftree-bit-ccp  -ftree-builtin-call-dce -ftree-ccp -ftree-ch -ftree-copyrename -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre -ftree-phiprop -ftree-slsr -ftree-sra -ftree-pta -ftree-ter -funit-at-a-time -fthread-jumps -falign-functions  -falign-jumps -falign-loops  -falign-labels -fcaller-saves -fcrossjumping -fcse-follow-jumps  -fcse-skip-blocks -fdelete-null-pointer-checks -fdevirtualize -fexpensive-optimizations -fgcse  -fgcse-lm  -fhoist-adjacent-loads -finline-small-functions -findirect-inlining -fipa-sra -foptimize-sibling-calls -fpartial-inlining -fpeephole2 -fregmove  -freorder-blocks  -freorder-functions -frerun-cse-after-loop -fsched-interblock  -fsched-spec -fschedule-insns  -fschedule-insns2 -fstrict-aliasing -fstrict-overflow -ftree-switch-conversion -ftree-tail-merge -ftree-pre -ftree-vrp -c test.c -o obj.o
    TIMEFORMAT='%3R' &&  time(./obj.o)
execution time = 2.652

我的问题是为什么执行时间不同,我应用了相同的优化?

更新

如果(根据 GCC 文档):

并非所有优化都直接由标志控制。

那么研究人员如何使用比标准优化序列更快的方法来重现优化序列(使用进化算法,他们 用于生成数千个优化序列并收集这些 对执行时间的影响最大)

例如“Acovea”http://hg.ahs3.net/acovea/debian/html/acoveaga.html

和“科尔”http://users.elis.ugent.be/~leeckhou/papers/cgo08.pdf

【问题讨论】:

  • 可能有更令人满意的解释,但在抢占式多任务系统(例如,所有桌面、移动和服务器)上,总是有可能发生其他事情。通常,人们倾向于运行许多计时测试并将它们平均以获得更有用的数字,这些数字不受备份软件的支配:)。
  • 文档上写着Depending on the target and how GCC was configured, a slightly different set of optimizations may be enabled at each -O level than those listed here. You can invoke GCC with -Q --help=optimizers to find out the exact set of optimizations that are enabled at each level. ...你试过-Q --help=optimizers
  • @user2357112 -fdelayed-branch 用于 Fortran。我不需要它。我只删除了这个选项
  • @staticx:Fortran?我认为分支延迟没有任何特定于语言的内容。当然,特定于架构 - 我不认为延迟分支在 x86 上是一个问题 - 但它可能无论如何都会影响某些东西。
  • 由于代码相同,您的问题似乎毫无意义。你的测量方法显然是错误的。提供minimal reproducible example

标签: c performance gcc compiler-optimization execution-time


【解决方案1】:

您是否知道程序的唯一内存布局可以产生高达 40% 的巨大性能影响?以下是一些相当愚蠢的事情,它们会改变应用程序的内存布局:

  • 链接时链接外部库的顺序
  • 运行时环境变量的数量和内容
  • 运行二进制文件的目录名称

是的,我不是在开玩笑。仅仅因为您从位置 A 而不是位置 B 运行相同的二进制文件,它的运行速度可能会快/慢 40%,因为路径被推送到堆栈,因此它的长度会改变堆栈布局,这会影响兑现、分支预测、等等

如今,大多数衡量绩效的人都做错了。与几年前相比,Profilers 的用处要小得多,当时 CPU 仍然线性扩展。

这是一个关于性能的视频,可以真正让您了解该主题以及如何正确衡量它:

https://www.youtube.com/watch?v=r-TLSBdHe1A

我强烈建议每位低级程序员观看该视频。 42分钟,真的很值得一看。他们还向您展示了一些免费工具,您可以使用它们来衡量性能改进,而不会陷入统计欺骗。

是的,它直接解决了您的问题,即编译器开发人员如何知道 O2 真的比 O1 更好,或者他们真的知道吗?事实上,情况并非总是如此。

性能优化是一件很脆弱的事情,优化让您的应用在一个系统上运行得更快可能会对另一个系统产生相反的影响,因此对于真正的优化,您需要计算运行时变化只是巧合的可能性有多大因为像内存布局这样的东西已经改变或者是一个真正的、实际的改进。视频中也简要介绍了该主题。

除了这个视频,我只能建议你看看生成的汇编代码。如果代码不同,则可以解释运行时差异,并提供优化如何不同的提示。也许这一切都归结为过时的文档,实际上 O2 只是打开/关闭未提及的标志。如果代码是相同的,也许它只是在喜欢期间发生的巧合效应之一。

所以尝试将-S 添加到gcc 调用并比较生成的汇编代码。

【讨论】:

    【解决方案2】:

    最后我检查了一下,传递 -O2 所暗示的所有选项(但不是任何 -O 选项)仍然没有阻止 GCC 在语句之间将值溢出/重新加载到内存中,即用于一致调试的调试模式行为。所以默认-O0 的那部分仍然打开。
    (Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?) 如果您查看 asm 输出,这将是显而易见的:
    How to remove "noise" from GCC/clang assembly output?

    这当然是性能上的全部垃圾,尽管具有乱序执行的现代 CPU 可以根据程序隐藏一些存储/重新加载延迟。

    所以如果你想让 GCC 努力优化你的代码,总是以-O3 开头(如果你只想在这台机器上运行它最好是-march=native,也希望@ 987654328@ 或启用跨文件内联的东西)。

    然后看看添加更多-f 和/或-m 选项到-O3,如果有一些没有作为-O3 的一部分启用。 (例如-funroll-loops,这可能会使大型程序的情况变得更糟,因此仅作为配置文件引导优化的一部分默认启用,-fprofile-generate/使用一些代表性输入运行至少一次/@ 987654335@.)

    【讨论】:

      【解决方案3】:

      有2个很好的优化应该知道:

      • -O2:优化空间和时间(注意:不初始化变量)
      • -Os:优化空间和时间(注意:不初始化变量)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-05
        • 2023-03-30
        • 2011-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-02
        • 2010-10-30
        相关资源
        最近更新 更多