Bru*_*ior 3 optimization gcc clang
我正在寻找针对我的特定代码的最佳优化标志。通过谷歌搜索一段时间,我发现没有选择最佳优化的黄金法则。答案取决于具体的代码、编译器和机器。
建议的优化标志是-O2,尽管在某些情况下 -Os(为了生成更小的二进制文件)可能会生成执行速度更快的二进制文件。-O3我更喜欢忽略高级优化的使用,因为在某些情况下它可能是危险的。在某些情况下,-O2与-Os标志结合会产生更好的结果。或者在其他情况下,编译-march=native为特定机器提供优化的二进制文件(因此它可以生成执行时间更短的二进制文件)。
对于我的特定代码(使用valgrind --tool=calgrind和perf stat),我发现它-march=native不会生成最短的运行时间。
现在,我的问题是:
如果对于我的特定代码,我发现最佳二进制文件(我的意思是,产生更快执行时间的二进制文件)是使用
-Osand/or生成的-O2,这在其他机器上将是最佳的?
我只想在一台计算机上确定最佳优化标志,但我必须在不同的计算机上运行(一台计算机使用 MacOS,另一台计算机使用 Linux,并且所有计算机的操作系统版本都不同)。
预先感谢您的任何建议或想法。
TL:DR:不,不同的 CPU 喜欢不同的东西。如果编译器只能低效地完成自动矢量化,那么自动矢量化可能在一台机器上是胜利,但在另一台机器上却是失败。
gcc -O2 -march=native或者gcc -O3 -march=native都是值得尝试的好选择。或者更好的是,这些 + 链接时优化和/或配置文件引导优化,以便编译器知道哪些循环是热的,哪些分支通常只走一种方式,哪些分支是不可预测的。
我不知道你是否曾经gcc -march=native在没有-O选项的情况下尝试过,但这不会有用;-march=native使用默认值-O0仍然会是垃圾。
-O3值得尝试。clang 手册页说它有时会使代码变得更大,所以要小心它,并进行基准测试以确保您的代码确实更快。就性能而言,这只是“风险”,而不是正确性。如果没有其他选项来专门启用不安全的优化,编译器不会改变语言规则。
Clang 文档说-O4目前相当于-O3
至少对于 gcc,自动矢量化仅在-O3. Clang 可能还有其他只发生在 的好东西-O3。
我不确定“一般使用”建议是否仍然是唯一的-O2,或者是否-O3通常足够保守以一直使用。使用-fprofile-generate/ -fprofile-use,编译器应避免使不经常运行的路径的代码大小膨胀,并且仅展开实际上很热的循环。
如果perf显示任何 I-cache 未命中,则-Os值得尝试。也许-Os对于大多数源文件,以及-O3具有最热门函数的源文件。
clang -O3进行一些循环展开,但gcc -O3不启用循环展开-fprofile-use(或者-funroll-loops,当然)。
还有-Ofast,它可能会导致不安全的优化。如果你的代码仍然可以正常工作,那就继续吧。(我认为unsafe大多数意味着可能会以不同的方式溢出。对于 FP 代码,如果您不关心代码在存在 NaN / Inf 时的具体行为,或者不关心确切的操作顺序,那么您可以使用-Ofast(或只是-O3 -ffast-math)。
如果我想花一些时间寻找最佳选项来编译我将花费大量 CPU 时间运行的东西,我要测试的东西列表绝对包括:
clang -O3 -march=nativeclang -O3 -march=native -fprofile-use (后... -fprofile-generate)-flto -emit-llvm(链接时优化,用于整个程序优化:源文件之间的内联函数(或者至少看看它们是否有副作用,即使没有内联)。) gcc-flto也有。gcc -O3 -march=native -fno-stack-protector -fprofile-use-ffast-math或什至-Ofast我想-Os也值得尝试。即使 I-cache / uop-cache 未命中不是问题,对齐的怪癖也会有所帮助。
如果-fomit-frame-pointer不是编译器中的默认值,也可以使用它来释放额外的整数寄存器并缩短函数序言/结尾。
如果您想在所有机器上使用相同的二进制文件,那么-march=some_baseline -mtune=something. (假设 clang 共享 gcc 的 arch/tune 选项。)
或者只是-msse4.2 -mtune=sandybridge什么。我认为,只要您构建 x86-64 二进制文件,编译器就只会对新的 SSE 指令感兴趣。(不是 popcnt、BMI 等)
另一种方法是在每台计算机的主目录中检出源代码,并使用本地编译器构建程序。但是,如果您在一台机器上有一个真正新版本的 gcc 或 clang,或者英特尔的编译器,那么只使用它是有意义的。
您还可以查看 auto-parallelization: gcc -ftree-parallelize-loops=n,其中n是要使用的线程数。
所有这些需要注意的是,我听说过代码破坏,-O3因为它依赖于语言规则不需要的行为。因此积极的优化找到了一种优化方法,使代码不再做同样的事情。如果您希望代码运行得更快,请确保避免未定义的行为,以便可以全程调高优化器。(IIRC,最近有一个关于检查编译器何时基于假设优化某些内容的问题,因为否则会发生未定义的行为。)
| 归档时间: |
|
| 查看次数: |
1351 次 |
| 最近记录: |