NTUGIEE_EDA 板


LINE

Optimizing Code with GCC (感谢aknow提供:http://blog.csdn.net/daidodo/archive/2008/03/15/2185222.aspx ) 现在的编译器越来越聪明,功能越来越强,从简单的函数内联,到复杂的寄存器分析,一 系列代码革命使程序运行得越来越快。大多数时候,更快比更小重要,因为磁盘空间和内 存都变得便宜了。但是在嵌入式系统里,更小和更快是一样重要的,所以把代码进行优化 是非常有意义的工作。 如果你已经知道了怎样用gcc编译你的代码,现在是时候让你的代码更快或者更小了,这 也是本章的内容。如果学有所成的话,你甚至可以让你的下一个程序既快又小。首先我们 快速浏览一下编译器优化理论,然後讨论GCC的代码优化命令行选项,从一般的、体系结 构无关的优化,到体系结构相关的优化方法。 虽然本章的示例代码都是C语言的,但是优化选项是通用的、语言无关的。能把一些优化 选项适用到所有语言的编译器上,是一个编译器家族最大的优势,比如GCC编译器家族就 是这样。 OPTIMIZATION AND DEBUGGING 没有代码优化的时候,GCC的一个重要目标是尽量缩短编译时间,并保证产生的代码在调 试环境下的行为正确。比如,在优化过的代码里,一个变量如果在循环里多次计算,但是 值其实没有变化,那麽编译器可以把它移到循环的外面,只计算一次。虽然这是可行了( 当然,只要不改变程序的运行结果),但是这使你无法按照源代码进行调试,因为计算该 变量的代码被优化掉了。如果没有优化,你就可以正确的进行调试,检查变量的值。这就 是所谓的「代码在调试环境下的行为正确」。 优化能改变代码的执行流程,但不改变执行结果。所以,优化一般是编码并调试完成之後 才进行的。其实优化过的代码也是可以进行调试的,只是需要一些技巧。 编译器优化理论概览 代码优化是指分析一段编译後的代码,然後决定如何改变它,使它运行的更快,消耗的资 源更少。拥有此功能的编译器叫做优化编译器(optimizing compilers),最後的输出代 码叫做优化代码(optimized code)。 优化编译器使用几种办法来决定哪些代码可被优化。一种是控制流分析(control flow analysis),即检查循环和其他控制语句,比如if-then和case,找出程序可能的执行路 径,然後决定哪些执行路径可以被改进。另一个典型的优化技术是检查数据是怎样使用的 ,即数据流分析(data flow analysis)。此法检查变量在哪里是怎样使用的(或没被使 用),然後应用一系列的方程式到这些使用模式上面,从而找到优化的途径。 除了本章所述的一些计算机所作的改进外,优化还包括了对程序所使用的算法的改进。典 型的比如冒泡排序算法改进成快速排序或希尔排序。这类改进能使程序的性能有本质的提 高,比计算机能做的优化强得多,所以优化既是CPU的事情,也是人的事情。 本节定义一个基本块(basic block)指,只有一个入口和出口,其他地方不包括终止、 分支语句的连续代码段。在一个基本块内进行的转化称为局部转化(local transformations),同样的不是在一个基本块内的转化称为全局转化(global transformations)。通常编译器会进行许多全局或局部的转化,不过局部转化总是先做 。 虽然本节的例子使用C语言,其实所有GCC编译器都使用一种中间语言进行这种转化,这种 中间语言比各种编程语言更适合计算机处理。GCC在产生最终的2进制代码前,会使用一系 列不同的中间语言翻译你的源程序。不过对人类来说,C和其他的高级语言比这些中间语 言更好理解。 GCC编译器还做了很多其他的优化,有些非常细致,甚至需要专业的编译器理论知识。这 里列出的优化方法只是基础,并且能用命令行来进行选择。 注意 我所知的最经典的编译器着作,当属「龙书」《Compilers: Principles, Techniques, and Tools》,因其封面有一个恐龙而得名(Alfred V. Aho, Ravi Sethi, and Jeffrey D. Ullman,Addison Wesley Longman, 1986. ISBN: 0-201-10088-6)。书里的优化理论 介绍比本文详细的多,并且曾是我的启蒙书籍。 Code Motion Code motion是一种优化技巧,是指在Common subexpression elimination(後有详述) 时去掉多余的代码。Code motion并不是去掉所有的subexpression,而是在中间语言形式 下改变它们的位置,以便能减少它们出现的次数。比如,在嵌套的循环或其他控制结构里 ,中间变量的计算次数可能不是最优的,要优化这些程序,编译器把这些计算语句移到循 环更少的地方,并且保证计算结果是一样的。把计算移出循环的方法我们称为 loop-invariant code motion。Code motion还用在另一种Common subexpression elimination里,叫做partial redundancy elimination。 Common Subexpression Elimination 去除多余的计算是一种标准的优化手段,因为它能减少程序的指令数,并得到相同的结果 。比如,如果一个表达式的参数(所引用的变量)值不变,那麽就可以只计算一次结果, 在以後引用该表达式的地方用结果值替代就可以了。这些後来引用该表达式的地方就叫做 common subexpressions。比如下例: Listing 5-1. An Example of a Common Subexpression #define STEP 3 #define SIZE 100 int i, j, k; int p[SIZE]; for (i = 0; i < SIZE; ++i) { j = 2 * STEP; k = p[i] * j; } for循环内的表达式j = 2 * STEP就是一个common subexpression,因为它的值可以在进 入循环之前计算,而且它的参数变量STEP(实际上是一个宏定义)从不改变。Common subexpression elimination (CSE)把for循环内的重复计算去掉,成为如下形式: j = 2 * STEP; for (i = 0; i < 100; ++i) { k = p[i] * j; } 虽然这个例子简单了点,不过能很好的说明问题,CSE去掉了100次对j的计算。CSE能去掉 不必要的计算,改善程序性能,并减少了最终文件的大小。 Constant Folding Constant folding是指去掉在编译时就能确定的数值计算表达式。这些表达式必须只包含 常数值,或者值为常数的变量。比如,下面的计算表达式都可以用一个赋值语句来替换: n = 10 * 20 * 400; i = 10; j = 20; ij = i * j; 後面的例子里,如果i和j在後续的程序里没有用到的话,完全可以去除它们的定义。 Copy Propagation Transformations 这是另一种减少或去除多余计算的方法,即去除那些只是为了传递数值的变量复制操作。 看下面的代码: i = 10; x[j] = i; y[MIN] = b; b = i; Copy propagation transformation可能会优化成下面的代码: i = 10; x[j] = 10; y[MIN] = b; b = 10; 在本例里,copy propagation允许把右值变成常数,这样比搜索和复制变量的值要快得多 ,并且也能去掉变量给自己赋值的情况。有些情况下,copy propagation并不直接产生优 化,但是能简化代码,方便其他优化,比如code motion和code elimination。 Constant propagation是一种把变量替换成常量的copy propagation transformation优 化方法。Copy propagation主要指去掉不必要的变量间的相互复制,而Constant propagation则指去掉不必要的预定义值到变量的复制。 Dead Code Elimination DCE是指把那些实际上无用的或多余的代码去掉。你可能想问「为什麽我会写这样的代码 呢?」,其实在一个很大的、延续时间很长的项目里,这是很容易发生的。许多DCE都是 在中间语言表示的形式下进行的,因为它是源代码更标准的翻译,更容易发现不必要的中 间计算。 Unreachable code elimination是指去除编译器确定不可能到达的代码。比如下面的代码 块: if ( i == 10 ) { . . . } else { . . . if ( i == 10) { . . . } } 第2次对i是否等於10的测试及处理代码可以去掉,因为它是不可能到达的。UCE也是在中 间代码形式里进行的。 If-Conversion 即分支重构,比如把大的if-then-elseif-else结构,重构成多个if语句,这样能简化代 码,为以後的优化提供方便,并去除某些无用的跳转和分支语句。 Inlining 即把复杂结构或函数调用替换成内联的代码以改善性能。Code inlining或loop unrolling都是指把全部或部分循环展开成一系列的直接指令。Function inlining是指用 函数执行的指令替代对函数的调用。一般情况下,inlining能减少代码复杂度,提高性能 ,因为不需要多余的分支跳转。它还能给common subexpression elimination和code motion提供优化机会。这方面最经典的例子是Duff』s Device,详见 http://en.wikipedia.org/wiki/Duff's_device。 GCC Optimization Basics GCC处理源代码时,会把它转化成一种中间形式。这样做有几大好处:、 l 把源代码变得简单、低级,使优化点暴露出来; l 使可能很复杂的结构更容易生成简单易读的语法分析树; l 使用统一的中间形式使GCC编译器之间能通用优化策略。 传统上GCC使用的内部中间形式叫做Register Transfer Language (RTL),这是一种很低 级的语言,GCC把任何代码(无论什麽级别)转化成目标代码之前都先翻译成这种代码。 对於像GCC的RTL这种非常低级的语言进行的优化也是很「低级」的,比如寄存器分配、堆 栈和数据优化等。因为它很低级,所以不会像你想像的那样能进行数据类型、数组和变量 引用、控制流改变等「高级」的优化。 GCC 4.0的作者们发明了一种新的中间形式static single assignment (SSA),通过对GCC 编译器产生的语法分析树进行操作而得到,因此得名Tree SSA。4.0及更高的GCC编译器在 生成Tree SSA之前还有2种中间形式,叫做GENERIC和GIMPLE。GENERIC是通过去除源代码 中语言相关的结构得到的中间形式,GIMPLE则是把GENERIC只读地址引用进行简化得到。 也许你也看出来了,在到达RTL等级之前,有许多的优化已经在这些相对高级点的层面上 先做了。 关於Tree SSA的详细信息和优化处理的步骤有许多资料可参考,其中一个是2003年的GCC 开发者总结,网址为 http://www.linux.org.uk/~ajh/gcc/gccsummit-2003-proceedings.pdf。 What』s New in GCC 4.x Optimization GCC 4.x家族最重要的变化是引入了中间形式Tree SSA,它提供了更多的优化空间,和更 多的参数选项,包括-ftree-ccp, -ftree-ch, -ftree-copyrename, -ftree-dce, -ftree-dominator-opts, -ftree-dse, -ftree-fre, -ftree-loop-im, -ftree-loop-ivcanon, -ftree-loop-linear, -ftree-loop-optimize, -ftree-lrs, -ftree-pre, -ftree-sra, -ftree-ter, and -ftree-vectorize,本章稍候会叙述。由於 有了这些重大的改变,原来的通用优化等级-O1、-O2、-O3和-Os都有了变化。除此以外, 任何语言的GCC编译器的优化都更普遍了。 同时由於有IBM的大力支持,GCC 4改进了向量化。向量化发现同一操作应用到多个数据的 代码,并改善其性能。GCC 4可以把16个标量操作合成为一个向量操作。这个优化方法可 以在游戏、视频和多媒体应用里大展身手,因为这些程序的指令都是对数组向量的重复操 作。 GCC 4还改进了数组边界检查和栈的内容结构检查,保护程序免遭流行的缓冲区和栈溢出 攻击。 Architecture-Independent Optimizations GCC的优化分为2大类:体系结构无关和体系结构相关。本节介绍体系结构无关的优化,包 括计算机体系无关,比如x86;处理器类型无关,比如IA-32处理器;和处理器家族无关, 例如Pentium IV (Xeon)。 GCC的优化选项有-O;-On,参数n是介於0到3之间的整数;或者-Os。-O0关闭优化。-O和 -O1(又叫作第1级优化)等价,允许编译器在不大量增加编译时间的前提下减少代码量和 执行时间。-O2和-O3比-O1的优化等级更高,-Os会最小化代码量。 本节所有的表格显示了GCC提供的各种优化选项,如果要关闭相应优化,只需在-f和优化 选项名字之间加上no-就行了。比如,要禁止deferred stack pops优化,命令行可以这样 写: $ gcc myprog.c -o myprog -O1 -fno-defer-pop 注意 -f表示一个机器无关的操作标志,即应用一个(大多数情况下)体系结构无关的优化操作 。这些标志选项更改了GCC的默认行为,但是不需要硬件的特殊支持。通常你可以指定多 个标志。 Level 1 GCC Optimizations 下表列出了-O或-O1时进行的默认优化选项: Optimization Description -fcprop-registers 试图减少寄存器复制操作的次数 -fdefer-pop Accumulates function arguments on the stack. -fdelayed-branch Utilizes instruction slots available after delayed branch instructions. -fguess-branch-probability 利用随机预测器猜测分支的可达性 -fif-conversion 把有条件跳转变成非分支语句 -fif-conversion2 利用条件执行(要求CPU支持)进行if-conversion优化 -floop-optimize 应用几个针对循环的优化 -fmerge-constants 合并多个模块中相等的常量 -fomit-frame-pointer 省略函数桢指针的存储。只能在不影响调试的系统里激活 -ftree-ccp 在SSA Trees上进行较少的conditional constant propagation(CCP)优化(只限GCC 4.x) -ftree-ch 在SSA Trees上执行loop header copying,即去掉一个跳转指令,并提供code motion优 化的机会(只限GCC 4.x) -ftree-copyrename 在SSA Trees上执行copy renaming,即在复制位置把内部变量的名字改得更接近原始变 量的名字(只限GCC 4.x) -ftree-dce 在SSA Trees上执行dead code elimination (DCE)优化(只限GCC 4.x) -ftree-dominator-opts 利用支配树(dominator tree)遍历来进行一系列优化。A dominator tree is a tree where each node』s children are the nodes that it immediately dominates。这些 优化包括constant/copy propagation,redundancy elimination,range propagation, expression simplification和jump threading(减少跳转语句)(只限GCC 4.x) -ftree-dse 在SSA Trees上执行dead store elimination (DSE) (只限GCC 4.x) -ftree-fre 在SSA Trees上执行full redundancy elimination (FRE),即认为全路径计算的表达式 会导致冗余编译。这和partial redundancy elimination(PRE)相似,不过比它快,找到 的冗余也比较少。(只限GCC 4.x) -ftree-lrs 在SSA Trees转化成RTL前,转化成一般形式,并执行live range splitting。这种方法 明确了变量的生存期,为後续的优化提供帮助(只限GCC 4.x) -ftree-sra 把聚合体替换成标量,即把对结构体的引用替换成标量数值,避免在不必要的时候把结 构体提交到内存里(只限GCC 4.x) -ftree-ter 在SSA Trees转化成RTL前,转化成一般形式,并执行temporary expression replacement (TER)。把只使用一次的临时表达式替换成原始定义的表达式,这样更容易 产生RTL代码,并使产生的RTL代码有更多的优化机会。(只限GCC 4.x) 第1级优化揉合了代码大小和速度改进2种优化措施。比如,-tree-dce去掉了无用代码, 於是减少了代码量;跳转指令减少使整个程序的栈使用量减少;而-fcprop-registers是 性能优化,减少在寄存器间复制数据的次数。 -fdelayed-branch和-fguess-branch-probability是指令调度改进。如果底层CPU支持指 令调度,这些优化标志就试图使CPU等待下一条指令的等待时间最小化。 -floop-optimize开启了对循环的优化,包括把常数表达式移出循环和简化推出循环的条 件测试。在更高的第2级优化里,该标志还执行strength reduction和循环展开。 -fomit-frame-pointer是非常有用,原因有2个:省下了设置、保存和恢复桢指针的代码 ;有时候省下了一个CPU寄存器,可有它用。而负面影响是:没有了桢指针,调试(比如 栈跟踪,尤其是嵌套很深的函数)变得很难甚至不可能。 -O2优化(第2级优化)包括了第1级的所有优化加上下表列出的另一些优化。应用这些优 化将延长编译时间,不过你的程序性能将得到显着的提高。 Level 2 GCC Optimizations 当使用-O2优化选项时,下表的优化将默认进行: Optimization Description -falign-functions 把函数对齐到2的指数字节边界 -falign-jumps 把跳转指令对齐到2的指数字节边界 -falign-labels 把标签对齐到2的指数字节边界 -falign-loops 把循环对齐到2的指数字节边界 -fcaller-saves 保存并恢复被函数调用改写的寄存器 -fcrossjumping 分解等价代码来减少代码量 -fcse-follow-jumps CSE过程中跳过不会到达的目标 -fcse-skip-blocks CSE过程中可以跳过条件块 -fdelete-null-pointer-checks 去掉不必要的null指针检查 -fexpensive-optimizations 执行一些「较昂贵」的优化 -fforce-mem 在寄存器里保存内存操作数(只限GCC 4.1) -fgcse 执行一遍全局CSE(Common Subexpression Elimination) -fgcse-lm 在全局CSE时把装载指令移到循环外面 -fgcse-sm 在全局CSE时把保存治疗移到循环外面 -foptimize-sibling-calls 优化有副作用的或尾递归的函数调用 -fpeephole2 执行机器相关的深度优化 -fregmove Reassigns register numbers for maximum register tying -freorder-blocks 重新安排函数的基本块,以便减少分支和提高代码局部性 -freorder-functions 对於经常调用或极少调用的函数,使用特殊的text段重新安排函数的基本块,以提高代 码局部性 -frerun-cse-after-loop 在循环优化之後执行一遍CSE -frerun-loop-opt 执行2此循环优化 -fsched-interblock 在基本块间调度指令 -fsched-spec Schedules speculative execution of nonload instructions -fschedule-insns 重新安排指令以最小化执行延迟 -fschedule-insns2 执行第2次schedule-insns -fstrength-reduce 用「廉价」的指令代替「昂贵」的指令 -fstrict-aliasing 通知编译器使用最严格的别名规则(aliasing rules) -fthread-jumps 试图重新安排跳转指令的顺序,成为执行的顺序 -ftree-pre 在SSA Trees上执行partial redundancy elimination (PRE) -funit-at-a-time 在开始代码生成之前对整个文件进行语法分析,以便进行额外的优化,比如重新安排代 码和申明,去掉从不引用的静态变量和函数等。 -fweb 把每个web(代码的存活范围)赋给它自己的伪寄存器,方便後续的优化,例如CSE, dead code elimination和循环优化。 4个-falign-选项强制函数、跳转指令、标签和循环对齐到2的指数边界,原理是内存对齐 的数据和结构对计算机有更高的访问速度。前提是对齐後的代码被频繁调用,能弥补因对 齐造成的no-op指令的延迟。 -fcse-follow-jumps和-fcse-skip-blocks正如其名,是在前面介绍的CSE过程中执行的优 化。使用-fcse-follow-jumps,CSE会跳过不可到达的目标代码。比如,下面的条件代码 : if (i < 10) { foo(); } else { bar(); } 通常,即使(i < 10)测试为false,CSE仍要按照全路径对foo()进行优化。如果你指定了 -fcse-follow-jumps,CSE就直接跳到else块进行优化(bar())。 -fcse-skip-blocks使CSE可以跳过条件块。比如你写了如下的if语句: if (i >= 0) { j = foo(i); } bar(j); 如果你指定了-fcse-skip-blocks而且i是负值,那麽CSE将直接跳到bar(),越过了原来的 if语句。而通常情况下,无论i是什麽值,CSE都需要对if语句进行处理。 -fpeephole2执行CPU相关的深度优化,把较长的指令集替换成较短的、简练的指令。比如 下面的代码: a = 2; for (i = 1; i < 10; ++i) a += 2; GCC可能把整个循环替换成赋值语句a=20。使用了-fpeephole2,GCC就在标准的深度优化 (比如C语言里用位操作代替算术操作)之外还进行CPU相关的优化。 -fforce-mem是指在对指针进行运算前,把内存操作数和常量复制到寄存器里,目的是生 成内存引用的common subexpressions,然後用CSE进行优化。前面已经讲过,CSE能去除 多余的寄存器装载指令。 -foptimize-sibling-calls试图优化掉尾递归的或同属调用(sibling call)的函数。尾 递归调用是指函数的递归调用出现在最後面。比如下面的代码: int inc(int i) { printf("%d\n" i); if(i < 10) inc(i + 1); } 上面定义的inc()函数,在函数体最後递归调用了以i+1为参数的自身,直到i大於等於10 。既然尾递归调用的深度是已知的,那麽就可以用一个迭代来消除尾递归。 -foptimize-sibling-calls就试图进行这种优化。同属调用(sibling call)也是指函数 调用出现在尾上下文(tail context,比如return语句)中。 GCC Optimizations for Code Size 选项-Os变得越来越流行,因为它包含了第2级优化里除增加代码量以外的所有优化。-Os 还应用了一些减少代码量的额外优化。代码量在这里不是指程序文件在磁盘里占用的存储 空间,而是指程序运行时占用的内存空间。注意,-Os会自动屏蔽下面的优化选项: ‧ -falign-functions ‧ -falign-jumps ‧ -falign-labels ‧ -falign-loops ‧ -fprefetch-loop-arrays ‧ -freorder-blocks ‧ -freorder-blocks-and-partition ‧ -ftree-ch 分别使用-O2和-Os编译程序,然後对比它们的性能和内存用量是很有意义的。比如,我发 现最新的Linux内核下使用-O2和-Os编译的程序拥有几乎相同的运行时性能,但是後者的 运行时内存用量却少了15%。当然,你的环境下可能有不同的发现。 Level 3 GCC Optimizations 指定-O3优化选项除了包括第1级,第2级的所有优化外,还包括: l -fgcse-after-reload:在重新装载时执行一遍额外的load elimination; l -finline-functions:把所有的「简单」函数内联到调用者中; l -funswitch-loops:Moves branches with loop invariant conditions out of loops 注意 如果使用了多个-O选项,最後的那个决定一切。所以,命令gcc -O3 foo.c bar.c -O0 -o baz将不执行任何优化,因为-O0出现在最後。 Manual GCC Optimization Flags 除了前面讲的几个-O选项能进行的优化外,GCC还有几个只能用-f指定的优化选项,如下 表所示: Flag Description -fbounds-check 对访问数组的索引进行检查 -fdefault-inline 把C++成员函数默认为内联 -ffast-math 设置: -fno-math-errno -funsafe-math-optimizations -fno-trapping-math 选项 -ffinite-math-only 禁止检查NaN和无穷大的参数或结果 -ffloat-store 禁止在寄存器里存储浮点数值 -fforce-addr 在寄存器里存储内存常量 -ffunction-cse 在寄存器里存储函数地址 -finline 把用inline关键字指定的函数内联展开 -finline-functions 在调用者里把简单的函数内联 -finline-limit=n 指定内联函数的伪指令数不超过n -fkeep-inline-functions 保持内联函数仍为可调用的函数 -fkeep-static-consts 保留用static const申明但从未引用过的变量 -fmath-errno 设置数学函数的errno执行时成为单条指令 -fmerge-all-constants 把模块间相同值的变量合并 -ftrapping-math Emits code that generates user-visible traps for FP operations -ftrapv 产生代码捕捉有符号值的运算溢出 -funsafe-math-optimizations 禁止对浮点操作进行错误检查和一致性测试 上面列出的选项很多都有关浮点操作。在进行这些效果不确定的优化的同时,优化器会背 离严格的ISO和/或IEEE标准,尤其是对数学函数和浮点运算。在浮点运算量巨大的应用里 ,这样做可能有显着的性能提升,但是代价就是放弃了对标准的遵守。在某些情况下,这 种放弃是可以接受的,当然最终决定权在你的手里。 注意 不是所有的GCC优化选项都可以用这些标志来控制。有些优化选项是完全自动进行的,而 且只对代码进行小的修改。只要你使用了-O,就不能禁止这些优化。 Processor-Specific Optimizations 传统上,为目标机器定制的优化并不被提倡,因为它们依赖许多目标系统的信息。GCC利 用这些信息产生特殊的代码,使用处理器特有的属性或避免已知的缺陷。 在写这本书以前,我通常只用-O2来优化我的程序,把剩下的事都交给编译器。写完这本 书以後,我感觉自己的能力更强了,并给程序增加了一些被证明很有用的编译选项,即在 特定情况下的特定优化选项。下面的文字都是指导性的,因为毕竟你比我更懂自己的代码 。 Automating Optimization with Acovea 即使你把本文的内容忘的差不多了,你肯定还是知道GCC的选项简直有无数个。要想给某 一个特定的程序和特定的体系结构选择最好的GCC选项集,根本就是不可能的。所以很多 人都做法是,使用标准的优化选项,然後在自己知道的其他选项里试验出几个有用的。这 样做可能是为了节省开发时间,但是它却是「可耻」的。 Scott Ladd的Acovea程序(http://www.coyotegulch.com/products/acovea/index.html )提供了一个有趣而且有用的方法,获得最好的优化选择,原理是利用进化算法( evolutionary algorithm)模拟自然的选择。听起来似乎很神奇,让我们看看它是怎麽工 作的。Acovea应用那些可能改善各种代码的优化算法,检查结果,然後保留那些能使代码 性能提高的优化。这和自然选择过程的第一步在概念上非常相似。Acovea然後自动把满意 的优化算法传给後续的选择过程,这样一步步应用更多的优化算法。 GCC专家们在网上各处发表了很多进化出「最佳」优化的建议。不过,这些建议可能是相 互矛盾的,甚至在你的应用里不产生效果。Acovea试图通过反覆的用优化选项编译代码, 并自动详细的分析性能,来得到最佳的结果。这种详尽的分析经历可以使你学习GCC优化 选项中最难懂的部分——选项之间的相互影响。Acovea使你可以自动测试所有的GCC选项 组合,帮助你大大加快开发过程,得到最少或编译最快的程序版本。 Building Acovea 你可以从http://www.coyotegulch.com/products/acovea/index.html上得到Acovea的最 新版本。安装Acovea前需要2个额外的库: l coyotl:包含了Acovea用到的许多函数,包括一个定制的随机数生成器,底层的浮点 应用,一个通用的命令行分析器,和改良的排序和验证工具; l evocosm:提供了开发进化算法的一个框架。 然後使用简单的解压、配置、安装流程就行了。最後的可执行程序runacovea位於 /usr/local/bin(默认)下。 注意 Acovea只支持类Unix和Linux的系统,对Cygwin的支持可能还需要点工作。 Configuring and Running Acovea Acovea为你的程序进行的测试选项定义在XML格式的配置文件里,配置文件的模板可以在 http://www.coyotegulch.com/products/acovea/acovea-config.html得到。GCC的版本对 这些配置文件非常重要,所以首先得到和你GCC版本相符的配置文件;其次是处理器的类 型。下面是一个Acovea配置文件的范例: <?xml version="1.0"?> <acovea_config> <acovea version="5.2.0" /> <description value="gcc 4.1 Opteron (AMD64/x86_64)" /> <quoted_options value="false" /> <prime command="gcc" flags="-lrt -lm -std=gnu99 -O1 -march=opteron ACOVEA_OPTIONS -o ACOVEA_OUTPUT ACOVEA_INPUT" /> <baseline description="-O1" command="gcc" flags="-lrt -lm -std=gnu99 -O1 -march=opteron -o ACOVEA_OUTPUT ACOVEA_INPUT" /> <baseline description="-O2" command="gcc" flags="-lrt -lm -std=gnu99 -O2 -march=opteron -o ACOVEA_OUTPUT ACOVEA_INPUT" /> <baseline description="-O3" command="gcc" flags="-lrt -lm -std=gnu99 -O3 -march=opteron -o ACOVEA_OUTPUT ACOVEA_INPUT" /> <baseline description="-O3 -ffast-math" command="gcc" flags="-lrt -lm -std=gnu99 -O3 -march=opteron -ffast-math -o ACOVEA_OUTPUT ACOVEA_INPUT" /> <baseline description="-Os" command="gcc" flags="-lrt -lm -std=gnu99 -Os -march=opteron -o ACOVEA_OUTPUT ACOVEA_INPUT" /> <!-- A list of flags that will be "evolved" by ACOVEA (85 for GCC 4.1!) --> <flags> <!-- O1 options (these turn off options implied by -O1) --> <flag type="simple" value="-fno-merge-constants" /> <flag type="simple" value="-fno-defer-pop" /> <flag type="simple" value="-fno-thread-jumps" /> <flag type="enum" value="-fno-omit-frame-pointer|-momit-leaf-frame-pointer" /> <flag type="simple" value="-fno-guess-branch-probability" /> <flag type="simple" value="-fno-cprop-registers" /> <flag type="simple" value="-fno-if-conversion" /> . . .. <!-- O2 options --> <flag type="simple" value="-fcrossjumping" /> <flag type="simple" value="-foptimize-sibling-calls" /> <flag type="simple" value="-fcse-follow-jumps" /> <flag type="simple" value="-fcse-skip-blocks" /> <flag type="simple" value="-fgcse" /> <flag type="simple" value="-fexpensive-optimizations" /> <flag type="simple" value="-fstrength-reduce" /> <flag type="simple" value="-frerun-cse-after-loop" /> <flag type="simple" value="-frerun-loop-opt" /> … <!-- O3 options --> <flag type="simple" value="-fgcse-after-reload" /> <flag type="simple" value="-finline-functions" /> <flag type="simple" value="-funswitch-loops" /> … <!-- Additional options --> <flag type="simple" value="-ffloat-store" /> <flag type="simple" value="-fprefetch-loop-arrays" /> <flag type="simple" value="-fno-inline" /> <flag type="simple" value="-fpeel-loops" /> … <!-- Tuning options that have a numeric value --> <flag type="tuning" value="-finline-limit" default="600" min="100" max="10000" step="100" separator="=" /> </flags> </acovea_config> 注意 Acovea可以用於任何GCC编译,只要给baseline属性的command元素赋相应的值就行了。 当你准备好了配置文件後,就可以使用runacovea程序进行测试: runacovea –config config-file-name –input source-file-name 注意 默认情况下,Acovea把速度和性能放在首位,不过也可以指定-size选项使runacovea首先 优化代码量。 执行runacovea能得到很多的输出,因为它使用许多优化的排列组合进行测试,最终的输 出可能是如下样子: Acovea completed its analysis at 2005 Nov 24 08:45:34 Optimistic options: -fno-defer-pop (2.551) -fmerge-constants (1.774) -fcse-follow-jumps (1.725) -fthread-jumps (1.822) Pessimistic options: -fcaller-saves (-1.824) -funswitch-loops (-1.581) -funroll-loops (-2.262) -fbranch-target-load-optimize2 (-2.31) -fgcse-sm (-1.533) -ftree-loop-ivcanon (-1.824) -mfpmath=387 (-2.31) -mfpmath=sse (-1.581) Acovea's Best-of-the-Best: gcc -lrt -lm -std=gnu99 -O1 -march=opteron -fno-merge-constants -fno-defer-pop -momit-leaf-frame-pointer -fno-if-conversion -fno-loop-optimize -ftree-ccp -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-copyrename -ftree-fre -ftree-ch -fmerge-constants -fcrossjumping -fcse-follow-jumps -fpeephole2 -fschedule-insns2 -fstrict-aliasing -fthread-jumps -fgcse-lm -fsched-interblock -fsched-spec -freorder-functions -funit-at-a-time -falign-functions -falign-jumps -falign-loops -falign-labels -ftree-pre -finline-functions -fgcse-after-reload -fno-inline -fpeel-loops -funswitch-loops -funroll-all-loops -fno-function-cse -fgcse-las -ftree-vectorize -mno-push-args -mno-align-stringops -minline-all-stringops -mfpmath=sse,387 -funsafe-math-optimizations -finline-limit=600 -o /tmp/ACOVEAA7069796 fibonacci_all.c Acovea's Common Options: gcc -lrt -lm -std=gnu99 -O1 -march=opteron -fno-merge-constants -fno-defer-pop -momit-leaf-frame-pointer -fcse-follow-jumps -fthread-jumps -ftree-pre -o /tmp/ACOVEAAA635117 fibonacci_all.c -O1: gcc -lrt -lm -std=gnu99 -O1 -march=opteron -o /tmp/ACOVEA58D74660 fibonacci_all.c -O2: gcc -lrt -lm -std=gnu99 -O2 -march=opteron -o /tmp/ACOVEA065F6A10 fibonacci_all.c -O3: gcc -lrt -lm -std=gnu99 -O3 -march=opteron -o /tmp/ACOVEA934D7357 fibonacci_all.c -O3 -ffast-math: gcc -lrt -lm -std=gnu99 -O3 -march=opteron -ffast-math -o /tmp/ACOVEA408E67B6 fibonacci_all.c -Os: gcc -lrt -lm -std=gnu99 -Os -march=opteron -o /tmp/ACOVEAAB2E22A4 fibonacci_all.c 正如你所看到的,Acovea生成了一些最佳的优化选项组合列表,还有一些建议的GCC优化 选项信息。 前面也说过,靠手动详尽的测试所有GCC优化选项并找出它们之间的相互影响,需要相当 长的时间。Acovea的最大作用就是自动帮你来做这件事情。要更多的了解Acovea,请参考 http://www.coyotegulch.com/products/acovea。 -- .. S --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.112.5.65
1F:推 moonshade:这个有一大本文件的,我看了几页就没力了... 04/03 19:00







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:BabyMother站内搜寻

TOP