原文
LDC
:通过缓存
目标文件加速
增量构建
为了加快总编译时间,LDC1.1.0
可创建目标文件缓存
,第二次编译过程中,成功
查找缓存
时,可跳过优化
和构建机器代码
,从而显著减少
编译时间.
在大型代码基上测试,总构建时间从~3m30
(空缓存)减少到~2m30
(无更改,所有缓存命中
).只需要传递-ir2obj-cache=/tmp/ldccache
给LDC
,然后如下:
编译D程序
速度很快.这是它的卖点
之一.我第一次编译DMD+druntime+Phobos
(整个编译器和标准库
)时,它太快了,以至于我以为它在某个地方失败了!
使用DMD
编译很快.LDC
没有那么快,但它构建的代码比DMD
好得多.更好
的优化是有代价的.特别是对优化构建(-O3)
,优化
和构建机器代码
占据了LDC
总执行时间的最大份额
.
D
编译速度非常快,一般一次编译
所有内容就足够了.但对较大
项目,拆分为多个
并行线程来构建
是加快构建
速度的好方法.按多个
目标文件编译
项目,这些文件
在构建
结束时,再链接
在一起形成可执行文件.
对并行
构建过程,更改由许多
其他人导入
的文件中的一些代码
,并重启构建(增量
构建)编译导致大量重新.
所有导入
修改后文件
的文件都需要重新编译
,因为构建
系统只看到已更改导入
的文件,但不知道是否只是"本地"
更改(如,在非模板
函数中更改1
为2
)还是会影响
导入文件模块的非本地
更改(如更改
模板).
如果更改
是本地的,则不必重新
编译一堆文件
,因为构建的目标
文件与以前相同.用它来加速
增量构建.
优化
如下:一旦知道输出
与之前目标文件
完全相同,就跳过进一步编译
,只使用以前
目标文件.更通用
一点:一旦知道输出
与较早输出
相同,就中止
并使用较早
输出.
优化还加快了非并行非单目标
构建的速度,因为每个模块都按单独
目标文件编译
.
这些是ldc
的编译步骤:
1,解析输入文件为
模块;
2,语义
分析所有模块;
3,对每个模块,执行:
a
.构建LLVMIR
(构建IR
代码);
b
.运行LLVM
优化趟;
c
.输出目标
文件(LLVM
机器代码构建);
4,可选:把所有输出目标文件
链接到可执行
文件中.
可在分析语义
后,判断输出
是否会与以前
相同.分析语义
后,编译器知道足够
信息来识别
每个模块输出.
必须计算一个(几乎
)唯一标识目标文件
输出的"哈希"
.重新
编译后,重新
计算哈希并检查以前是否见过该哈希.当识别哈希时,使用先前构建的目标文件
并跳过3b
和3c
步骤.
没有明确定义
也不是简单序化
语义分析的"输出"
(修饰的AST
),因此很难
计算出好哈希.
但是,构建的LLVMIR
(3a
步骤),它的定义
非常明确,可用LLVMIR
序化来计算哈希
.只需要构建的LLVMIR
(加上-O3
等编译标志),就可创建目标
文件,并用它来避免与AST
更改相关的错误哈希
.
新的编译步骤是:
1,按模块
解析输入文件;
2,语义分析
所有模块;
3,对每个模块,执行:
a
.构建LLVMIR
(构建IR
代码);
b
.计算IR
哈希并查找缓存
.命中缓存
时,使用缓存
目标文件并继续
下个模块.
c
.运行LLVM
优化趟;
d
.输出目标文件(构建LLVM
机器代码);
e
.在缓存
中,按键使用b步骤
中计算的哈希
来存储
目标文件.
4,可选:把所有输出目标文件
链接到可执行
文件中.
哈希是使用LLVM
的MD5
哈希器计算的.直接喂送LLVM
二进制位码
表示到哈希器
中.其他哈希
输入包括编译器版本
,LLVM
版本和更改目标文件
输出(如优化级别
和目标CPU
)的命令行标志
.
如-g
或-d-version=Demo
的命令行标志不用于哈希;在3a
步骤中的构建LLVMIR
外,此类
标志没有影响.
可对所有项目
使用相同缓存
;且可与多个
用户共享缓存
.
代码
转为更改哈希
但是,用相同
目标文件输出,对两个LDC
调用找到哈希差
并不难.此D代码
可解决问题:
version (FIRST)
{
int foo(int a)
{
return a + 2;
}
}
else
{
int foo(int differentname)
{
return differentname + 2;
}
}
用和不用-d-version=FIRST
的编译输出
导致带不同哈希的相同
目标文件.
或:
version (FIRST)
{
void foo();
void bar();
}
else
{
void bar();
void foo();
}
要从缓存目标
文件中受益,只需传递-ir2obj-cache
命令行标志给LDC
:
ldc2 -ir2obj-cache=/tmp/ldccache
在/tmp/ldccache
中存储(ircache_
缓存文件.
有时需要缓存过期/修剪
方案.缓存修剪可由LDC(#1753)
使用--ir2obj-cache-prune
完成,也可用ldc-prune-cache
独立工具访问.
修剪
考虑缓存文件
的上次访问时间
,并试保持
最近访问文件
不变.默认最小
修剪间隔为20
分钟,这表明如果你试在上一次修剪
后的20
分钟内修剪,则不会有事情.
可轻松传递--ir2obj-cache-prune
给LDC
,而不必担心多个编译
线程同时修剪.
对并行构建,我建议在构建
过程结束时使用ldc-prune-cache
,而不是简单地添加,根据是否修剪
间隔已过去,在编译
完第一个文件
后缓存
修剪的--ir2obj-cache-prune
到D编译标志
中.