我应该使用哪些 gcc 优化标志?
Which gcc optimization flags should I use?
如果我想尽量减少我的 c 程序的时间 运行,我应该使用什么优化标志(我也想保持标准)
目前我正在使用:
-Wall -Wextra -pedantic -ansi -O3
我是否也应该使用
-std=c99
比如?
我是否有特定的命令应该将这些标志放在我的 makefile 中?这有什么区别吗?
还有,有什么理由不使用我能找到的所有优化标志吗?他们有没有互相反击之类的?
标志-std=c99
不会更改优化级别。它只会更改您希望编译器确认的目标语言标准。
当您希望编译器将您的程序视为 C99 程序时,您可以使用 -std=c99
。
在您指定的那些中,唯一与优化有关的标志是 -O3
。其他人则用于其他目的。
您可能想要添加 -funroll-loops
和 -fomit-frame-pointer
,但它们应该已经包含在 -O3
中。
如果需要,我建议使用 -std=gnu11
或 -std=c11
编译新代码。使所有 -Wall
警告静音通常是个好主意,IIRC。 -Wextra
警告您可能不想更改的某些内容。
检查编译结果的一个好方法是查看编译器 asm 输出。 http://gcc.godbolt.org/ 很好地格式化 asm 输出(去除噪音)。如果您完全了解 asm,那么将一些关键函数放在那里并查看不同编译器版本的作用会很有用。
使用新的编译器版本。 gcc 和 clang 在新版本中都有显着改进。 gcc 5.3 和 clang 3.8 是当前版本。在某些情况下,gcc5 的代码明显优于 gcc 4.9.3。
如果你只需要在你自己的机器上运行的二进制文件,你应该使用-O3 -march=native
.
如果您需要二进制文件 运行 在其他机器上 ,请选择指令集扩展的基线,例如 -mssse3 -mpopcnt
。您可以使用 -mtune=haswell
来针对 Haswell 进行优化,即使在较旧的 CPU 上编写仍然 运行 的代码(由 -march
确定)。
如果您的程序不依赖于严格的 FP 舍入行为,请使用 -ffast-math
。如果是这样,您通常仍然可以使用 -fno-math-errno
之类的东西,而无需启用 -funsafe-math-optimizations
。某些 FP 代码可以从快速数学中获得 大 加速,例如自动矢量化。
如果您可以对您的程序进行有用的测试运行,以练习需要针对实际 运行 优化的大部分代码路径,那么使用配置文件导向优化:
gcc -fprofile-generate -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
./my_program -option1 < test_input1
./my_program -option2 < test_input2
gcc -fprofile-use -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
-fprofile-use
启用 -funroll-loops
,因为它有足够的信息来决定何时实际展开。到处展开循环会使事情变得更糟。但是,值得一试 -funroll-loops
看看是否有帮助。
如果您的测试 运行 没有涵盖所有代码路径,那么一些重要的代码路径将被标记为 "cold" 并且优化较少。
-O3
启用自动矢量化,-O2
不启用。这可以大大加快速度
-fwhole-program
允许跨文件内联,但仅当您将所有源文件放在一个 gcc 命令行中时才有效。 -flto
是获得相同效果的另一种方法。 (Link-时间优化)。 clang 支持 -flto
但不支持 -fwhole-program
.
-fomit-frame-pointer
一段时间以来一直是 x86-64 的默认值,最近是 x86(32 位)的默认值。
除了 gcc,尝试用 clang 编译您的程序。 Clang 有时比 gcc 编写的代码更好,有时更差。尝试两者和基准测试。
如果我想尽量减少我的 c 程序的时间 运行,我应该使用什么优化标志(我也想保持标准)
目前我正在使用:
-Wall -Wextra -pedantic -ansi -O3
我是否也应该使用
-std=c99
比如?
我是否有特定的命令应该将这些标志放在我的 makefile 中?这有什么区别吗?
还有,有什么理由不使用我能找到的所有优化标志吗?他们有没有互相反击之类的?
标志-std=c99
不会更改优化级别。它只会更改您希望编译器确认的目标语言标准。
当您希望编译器将您的程序视为 C99 程序时,您可以使用 -std=c99
。
在您指定的那些中,唯一与优化有关的标志是 -O3
。其他人则用于其他目的。
您可能想要添加 -funroll-loops
和 -fomit-frame-pointer
,但它们应该已经包含在 -O3
中。
如果需要,我建议使用 -std=gnu11
或 -std=c11
编译新代码。使所有 -Wall
警告静音通常是个好主意,IIRC。 -Wextra
警告您可能不想更改的某些内容。
检查编译结果的一个好方法是查看编译器 asm 输出。 http://gcc.godbolt.org/ 很好地格式化 asm 输出(去除噪音)。如果您完全了解 asm,那么将一些关键函数放在那里并查看不同编译器版本的作用会很有用。
使用新的编译器版本。 gcc 和 clang 在新版本中都有显着改进。 gcc 5.3 和 clang 3.8 是当前版本。在某些情况下,gcc5 的代码明显优于 gcc 4.9.3。
如果你只需要在你自己的机器上运行的二进制文件,你应该使用-O3 -march=native
.
如果您需要二进制文件 运行 在其他机器上 ,请选择指令集扩展的基线,例如 -mssse3 -mpopcnt
。您可以使用 -mtune=haswell
来针对 Haswell 进行优化,即使在较旧的 CPU 上编写仍然 运行 的代码(由 -march
确定)。
如果您的程序不依赖于严格的 FP 舍入行为,请使用 -ffast-math
。如果是这样,您通常仍然可以使用 -fno-math-errno
之类的东西,而无需启用 -funsafe-math-optimizations
。某些 FP 代码可以从快速数学中获得 大 加速,例如自动矢量化。
如果您可以对您的程序进行有用的测试运行,以练习需要针对实际 运行 优化的大部分代码路径,那么使用配置文件导向优化:
gcc -fprofile-generate -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
./my_program -option1 < test_input1
./my_program -option2 < test_input2
gcc -fprofile-use -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
-fprofile-use
启用 -funroll-loops
,因为它有足够的信息来决定何时实际展开。到处展开循环会使事情变得更糟。但是,值得一试 -funroll-loops
看看是否有帮助。
如果您的测试 运行 没有涵盖所有代码路径,那么一些重要的代码路径将被标记为 "cold" 并且优化较少。
-O3
启用自动矢量化,-O2
不启用。这可以大大加快速度
-fwhole-program
允许跨文件内联,但仅当您将所有源文件放在一个 gcc 命令行中时才有效。 -flto
是获得相同效果的另一种方法。 (Link-时间优化)。 clang 支持 -flto
但不支持 -fwhole-program
.
-fomit-frame-pointer
一段时间以来一直是 x86-64 的默认值,最近是 x86(32 位)的默认值。
除了 gcc,尝试用 clang 编译您的程序。 Clang 有时比 gcc 编写的代码更好,有时更差。尝试两者和基准测试。