|
|
|
|
|
|
|
[Original]
[Print]
[Top]
|
LLVM: An Infrastructure for Multi-Stage Optimization
http://llvm.org/pubs/2004-01-30-CGO-LLVM.html
1. 传统的Link time 优化
Underlying idea: 获得尽可能多的信息来进行优化。
问题: at which level will the program be represented
(1) very low level
基本上是直接对机器码进行优化。比如 dynamo。
问题在于 机器码没有提供足够多的高层次信息。
通常的优化方法是:寄存器分配,inlining 和trace construction(trace的定义见 VM的书)
GCC3.4的RTL也类似,层次比较低。
(2)very high level (抽象语法树)
在编译单个文件的时候,将 源代码的 AST写入磁盘。连接的时候,取出这些源码的AST,然后进行优化,最后形成可执行文件。
优点:具有比较多的高层次信息,可以进行比较aggressive的优化。
缺点:1. 代价大。改变任何一个文件可能需要重新编译所有文件。
2. IR是专有的,不同的编译器和编译器不同版本之间的IR不兼容。
2, 传统的运行时优化
运行时优化可以得到 编译器所得不到的一些信息,比如控制流,hot path等。
(1) high level VM
比如SmallTalk Self Java and C#。字节码是比较高层次的(effective AST层次)。
问题:由于层次比较高,在compile 时优化方面显得不足。这就把优化的压力都推到了run time,增加了系统的负担。
(2) Architecture 层次的VM和Dynamic translator
要么是直接对 机器码进行优化,要么就是不同 指令集之间的translator。
基本上是依赖 profile,然后进行trace/superblock的优化。优化方法在《虚拟机——系统和进程的通用平台》 一书中比较多。
3. 传统的使用profile的compile-time 优化
既然profile 能提供程序的动态性能,那compile-time 也可以使用啊。
这样传统的编译过程就变成了如下5步
(1) 编译程序,增加插桩(Stub)用来收集profile。
(2) 将各个插桩过的程序链接形成instrumented executable。
(3) 运行程序,比如一些测试数据集合(Benchmark),获得profile
(4)(5) 用获得的profile信息重新编译程序。这次不需要插桩了。
问题:
(1) Profile信息只有在准备的情况下才有有价值的。实际的程序和benchmark还是有一些区别的。因此,采用benchmark的方式获得的profile不一定是准备的。
(2) 实际上,将原来编译程序的方式变成上面的5步后,太繁琐。程序员不愿意采用这种方式。
4. LLVM的多阶段优化
LLVM正是为了解决这些方法而设计的。
(1) 编译时优化:前端将源代码编译成LLVA - 低层次的表示方法却还保持了高层次的信息。实际上,就是对一般的RISC指令集进行了改造,加入了 高层次的信息。
(2) Link time:将多个源代码的object file链接成可执行文件,这个可执行文件是native code,,但是加入了LLVM的byte code。由于在LLVA bytecode中保持了一些高层次的信息,因此可以进行link time的优化。
(3) Runtime:运行程序(native code),获得profile。当VM发现能进行优化的时候,优化。既可以是直接修改可执行文件,也可以是修改附在可执行文件中的byte code。无论是哪一种情况,LLVM 的byte code都提供了重要的信息:高层次的控制流,数据流和type information,这些信息用来辅助进行aggressive的run time 优化。
(4) offline优化:由于有一些优化在run time进行的话,太耗费时间。因此,可以只将这些profile信息存入磁盘。当cpu比较空闲的时候,把这些profile信息拿出来,进行优化。称为Offline的优化。注意这个阶段的优化和link time的优化有一些类似,区别在于,offline有profile信息,而link time没有。由于profile是在程序实际运行的时候获得的,因此好处(1)profile信息准确。(2)不改变compile程序的一般流程。参考3。
|
|
|
----
|
|
[Original]
[Print]
[Top]
|
|
|