collide的专栏

http://202.113.13.41/stu_staff/douzhibin/index.htm

原创 CFLAGS祥解收藏

新一篇: linux---中国格局 | 旧一篇: linux下各种后缀名解压

CFLAGS 是决定 Gentoo 系统效能与稳定的关键之一。恰当的 CFLAGS 能在效能、编译时间、与系统稳定度中取得平衡,失败的 CFLAGS 可能导致编译失败,甚至系统损毁。那么,在茫茫 CFLAGS 海中,如何才能捞到命中注定那根针呢?

此文件的 CFLAGS 针对 x86 x86-64 平台上的 GCC 3.4 (GNU Compiler Collections - http://gcc.gnu.org/) 为主,若您使用其它编译器 ( icccompaq c compiler) 或其它平台 ( PowerPCAlpha),本章可能 50% 以上的东西您都用不上。

各位请先参考笔者从网络上整理出,有关服务器与工作站需求的信息。当然,服务器或桌面的需求绝对不只这些,这里仅列出跟设计 CFLAGS 比较有关的项目。以下是整理出的列表:

1.    服务器系统:

o   长时间启动 (一天 24 小时,一年 365 天,全年无休)

o   非常稳定 (uptime 99.999% [] 以上)

o   高安全性 (别怀疑,CFLAGS 跟安全性也有很大的关系)

o   在长时间启动的前提下,能自己照顾自己。

o   效能不是第一考虑

o   互动反应不用很快,够用就好。

2.    桌面、工作站:

o   启动时间没有那么长 (使用者要用的时候才开机)

o   可以不用那么稳定 (多半有使用者直接在处理,uptime 可以降到 99.99% 或更低)

o   效能也是考虑重点

o   互动反应快 (如加载一页网页,与其让他在三秒时整面显示出来,不如让它每秒显示一点可是在四秒时才全部显示完毕。)

所以,得到了桌面系统的 CFLAGS 设计要点:

1.    程序启动时间短

2.    反应速度快

3.    效能高

4.    稳定可以稍差 (容许范围内)

减少执行档的大小,可以同时减少了内存用量,也节省了一些磁盘空间。同时,桌面系统最大的效能瓶颈就在磁盘驱动器,减少档案大小也间接降低了磁盘的存取次数,可以加速程序的启动,提升第一次执行的反应速度。

[编辑]

CFLAGS 选项

再来,让我们看看 gcc 中关键的几个选项。这里只简单介绍这些选项的功能,若要详细说明请参考 man gcc

增加选项的数量,同时也增加编译的时间。所有的选项都会增加编译时间,有特别说明 "会增加编译时间" 的选项,表示会增加 "大量的" 编译时间 (跟其它选项比起来...)

[编辑]

比较安全的选项

首先是安全的选项:

·         指令

o   参数与用法 [注二]

o   说明

o   建议

·         -O

o   -O (-O1), -O0, -O2, -O3, -Os

o   依照后面数字的大小,针对效能最佳化的程度也不同 (稳定度也可能递减)。其中 -Os 是个比较特殊的等级,针对原始码大小最佳化。

o   可使用 -Os,降低程序加载的时间。

·         -fforce-mem
-fforce-addr

o   -fforce-mem, -fno-force-mem
-fforce-addr, -fno-force-addr

o   强制在运算前将内存中的数值 (mem) 或内存位置 (addr) 复制到缓存器中。启动这两个选项可以做出较好的程序代码。

o   这两个是好东西,启动它们!其中 -fforce-mem 已在 -O2, -O3, -Os 中启动,所以若您有用这三个选项的其中一个,只要 -fforce-addr 就够了。

·         -fomit-frame-pointer

o   -fomit-frame-pointer, -fno-omit-frame-pointer

o   若非必要,不将函式的 frame pointer 放进缓存器中。这将避免您的程序储存、设定、以及还原 frame pointer;也在许多函式中省下一个缓存器。这个选项可能让某些平台上的除错工作变成不可能!。若平台支持不使用 frame pointer 除错,这个选项将在 -O, -O2, -O3, -Os 中启动。

o   很抱歉,x86 刚好是非这个不可才能除错的平台之一。但是... 您想对您的桌面进行除错吗?若答案为非,您可以放心启动这个选项。

·         -finline-functions

o   -finline-functions, -fno-inline-functions

o   将所有简单的函式整合进呼叫他们的函式中。编译器会自动试探并决定那些函式值得被整合。于 -O3 时启动。

o   虽然这个选项会增加程序大小,但是他却是个增进效能的好东西。我建议您在这里启动它,然后使用下面一个指令指定 inline 条件。

·         -finline-limit

o   -finline-limit=n

o   n 为决定函式是否能被 inline 的伪指令长度。预设的值为 600

o   这个数值越小,程序启动的速度越快,但是运算的速度越慢。作为桌面使用,我建议 -finline-limit=400

·         -fmove-all-movables
-freduce-all-givs

o   -fmove-all-movables, -fno-move-all-moveables
-freduce-all-givs, -fno-redduse-all-givs

o   这两个是循环最佳化技术,将无关循环内容的运算改在循环外执行。编译出的执行档可能更快也可能更慢,结果跟程序的写法有很大的关系。

o   虽然说效能跟程序写法有关,但是大部份的状况下这两个选项会做出比较小与比较快的程序代码,所以我建议您启动他们!

·         -freorder-blocks
-freorder-functions

o   -freorder-blocks, -fno-reorder-blocks
-freorder-functions, -fno-reorder-functions

o   藉由重新编排程序区块来增进效能以及减少执行档大小。

o   这两个也是好东西,所以我建议您启动它们。缺点是会让编译时间变长。

o   -freorder-blocks -O2, -O3 时启动,于 -Os 中关闭。-freorder-functions -O2, -O3, -Os 时启动。

·         -fexpensive-optimizations

o   -fexpensive-optimizations, -fno-expensive-optimizations

o   执行几个会加长编译时间的非主要最佳化程序。于 -O2, -O3, -Os 中预设开启。

o   虽然会增加编译时间,但是能增加效能也能减少执行档大小,所以建议启用。

·         -falign-functions
-falign-labels
-falign-loops
-falign-jumps

o   -falign-functions, -falign-functions=n
-falign-labels, -falign-labels=n
-falign-loops, -falign-loops=n
-falign-jumps, -falign-jumps=n

o   依照大于 n 的最小 2 的次方字节对齐函式 (functions)、标签 (labels)、循环 (loops)、跳跃 (jumps) 的起头,跳过至多 n 字节。

o   我知道这很抽象,解释起来要花很多篇幅,所以请各位使用默认值,亦即指定 -falign-functions, -falign-labels, -falign-loops, -falign-jumps,但是不指定 =n。于 -O2, -O3 时启动。于 -Os 中关闭。

·         -frename-registers

o   -frename-registers, -fno-rename-registers

o   在作过缓存器定位之后,使用剩下来的缓存器。这个最佳化在有很多缓存器的 CPU 上最明显 ( ARMPowerPC... 等。x86 不属于他们的一份子)。会增加除错的困难度。

o   虽然在 x86 上不明显,但是还是有用。而且 x86-64 提供更多的缓存器,所以建议您还是应该打开它。于 -O3 时启动。

·         -fweb

o   -fweb, -fno-web

o   建立经常使用的缓存器网络。提供更佳的缓存器使用率。不过也会增加除错的困难度。

o   这个是安全选项中比较偏向实验性质的选项,虽然建议您启动,但是若启动之后程序不稳,请将它关闭。于 -O3 时启动。

实验性质的选项

以下是真的实验性质的东西,若启动之后系统不稳,请将他们关闭。

·         指令

o   参数与用法

o   说明

o   建议

·         -ffast-math

o   -ffast-math, -fno-fast-math

o   设定 -fno-math-errno, -funsafe-math-optimizations, -fno-trapping-math, -ffinite-math-only, -fno-rounding-math, 以及 -fno-signaling-nans 这几个选项,以及设定预先处理器的 __FAST_MATH__ 宏。这些技术虽然较快,但是违反 IEEE ISO 的规则,并且很有可能让程序算出错误的数值。

o   这是危险的东西,可能造成运算结果的错误 (1.1+1.2=1.4!?当然没那么离谱啦...),建议不使用。

·         -funit-at-a-time

o   -funit-at-a-time, -fno-unit-at-a-time

o   在制作执行文件前分析整个编译单位。提供某些额外最佳化套用的机会,但会使用更多内存。

o   这个东西还蛮安全的,请放心使用它!

·         -funroll-loops
-fold-unroll-loops

o   -funroll-loops, -fno-unroll-loops
-fold-unroll-loops, -fno-old-unroll-loops

o   展开可以在编译阶段决定次数的循环,可能让程序执行的更快或更慢。-fold-unroll-loops 使用旧的算法。

o   由于这个会让程序变大许多,所以建议不使用。

·         -funroll-all-loops
-fold-unroll-all-loops

o   -funroll-all-loops, -fno-unroll-all-loops
-fold-unroll-all-loops, -fno-old-unroll-all-loops

o   即使循环执行次数不确定,还是将所有循环展开。大部份状况下会让程序跑得更慢。

o   又比较慢又会变大,所以别用...

·         -fprefetch-loop-arrays

o   -fprefetch-loop-arrays, -fno-prefetch-loop-arrays

o   若目标机器支持,在存取大型数组循环执行之前预先将数组加载至内存。于 -Os 中关闭。

o   其实不太会有需要存取大型数组的循环 (多媒体、数据库、科学计算软件中才比较常见),所以您可以放心将此选项关闭。

·         -ffunction-sections
-fdata-sections

o   -ffunction-sections, -fno-function-sections
-fdata-sections, -fno-data-sections

o   将函式或资料物品放至自己的区段中。大部份使用 ELF 目标格式的系统以及执行 Solaris 2 SPARC 系统支持这些最佳化。会增加连结过程的时间,以及增加执行档大小,也会增加除错的困难。

o   在我的经验中,没有特别显著的效果,而且执行档会变大,所以建议不使用。

·         -fbranch-target-load-optimize
-fbranch-target-load-optimize2

o   -fbranch-target-load-optimize, -fno-branch-target-load-optimize
-fbranch-target-load-optimize2, -fno-branch-target-load-optimize2

o   在执行序启动以及结尾之前执行枝节目标缓存器加载最佳化。

o   这是进阶最佳化选项,建议您两个都启动。

平台相关选项

最后是 x86 x86-64 相关的选项:

·         指令

o   参数与用法

o   说明

o   建议

·         -mcpu (已过期,可能在以后版本中移除。)
-mtune
-march

o   -mcpu=cpu-type
-march=cpu-type
-mtune=cpu-type

o   依照不同的目标处理器进行最佳化。注意,若您指定了 -march,制作出的执行档将无法在其它 CPU 上使用。但是若光指定 -mtunegcc 会避免使用平台专有指令集跟专用排程选项。可用的选项有:

§        i386标准的 Intel i386 处理器

§        i486Intel i486 处理器 (没有排程实作)

§        i586, pentium:没有 MMX 指令集的 Intel Pentium 处理器