如何在2022年加速Rust编译器

2022-02-25 23:42:05

在2016年至2020年间,我写了一系列博客文章,名为“如何加速编译器”。这些主要是关于我在Rust编译器上的工作,以及关于Rust编译器总体速度的一些更新。

现在,我作为Futurewei的Rust团队的一员,回到了Rust潮流,是时候重新开始博客系列了。

#90746:这次公关改变了一个热门但非关键的断言!到一个调试断言!,这意味着它不会在Release构建中运行,在两个基准测试中获得高达5%的胜利。

#91246:Layout::array是一个函数,涉及向量增长,经常被实例化。这使得它更加简洁,减少了生成的LLVM IR的数量,在一些基准测试中,编译时间最多减少了4%,而在很多基准测试中,编译时间只提高了不到1%,尽管结果有点嘈杂。

#91844:该公共关系消除了债务导致的数据结构,降低了分配率,在许多基准测试中获得了低于1%的胜利。

hashbrown#305:rustc大量使用shash表,我发现大约三分之一的非修改哈希表查找都在空表上!hashbrown仍然会对输入进行散列,并在本例中执行正常的查找。如果表格是空的,这会改变它立即失败,一次赢11%,并且在1-4%的范围内抽签。这一变化后来作为#92998年hashbrown更新的一部分合并到了rustc中。

#91948:这篇与camelid合著的PR避免了因符号到字符串转换而在RustDoc中进行的大量分配,从而在所有RustDoc基准测试中获得了高达5%的好成绩。

#92604:这个PR优化了在元数据编码期间(再次)读取B128,从而在许多基准测试中获得高达3%的胜利。

#93066:为元数据解码而跟踪的解码器容易出错,在整个过程中使用结果。但是,只有在发生了非常意外的事情(例如元数据被破坏)时,解码才会失败,一旦失败,调用代码就会中止。这个PR改变了解码器,使其在整个过程中立即恐慌,而不是稍晚恐慌,从而避免了许多毫无意义的结果传播,因为在许多基准测试中获胜率高达2%。

#93148:rustc广泛使用interning、ForString和许多其他内部类型。内部类型被保证是唯一的,并且可以进行比较和廉价的散列(只考虑指针,而不是内容),但是一些内部类型没有利用这一点。这项大型公关改革了用于实习的类型,使其更加一致,赢得了高达4%的许多基准。

我试图通过更改新令牌中第一个字符的处理来加速externs Stress Test的词法分析,但没有任何帮助。

我尝试缩小各种分配给竞技场的类型,比如Ty和Predicate,但这并没有起到足够的作用。

我为MIR起草了一份死区消除优化通行证,灵感来自于与丢弃标志相关的明显冗余代码的存在。这是可行的,但可测量的性能优势微不足道,不值得额外的代码。

我尝试了各种方法来改进使用ast::PathSeg和AttrVec的向量表示,但都没有成功。

我试图进一步优化与向量增长相关的代码,以最小化LLVM IR生成,但未能以不降低编译代码速度的方式实现。

我尝试将非空哈希表的最小容量从3更改为7。这带来了一些小的(1-2%)性能提升,但将峰值内存使用率提高了更多(5-10%),因此不值得这么做。

我尝试了很多方法来改进rustc哈希表使用的FxHasher算法,但没有成功。

我尝试增加StableHasher使用的缓冲区大小,这与增量编译一起使用,但导致性能略有下降。

我尝试了一些调整:预实习一些常见的InternedValue,缓存一些最近实习的值,以及避免实习符号时的双重查找。他们都没帮上忙。

我试着加快寻找图书馆板条箱的速度,但失败了,尽管我一路上做了一些清理工作。

我尝试了很多方法让jemalloc提供分配块的准确实际大小,但没有成功。(各种锈迹和jemallocAPI边界的设计使这项任务比我希望的更困难。)我还试用了jemalloc的“大小交易”功能,有几个人向我保证这将是一场胜利,但它减慢了速度。jemallocis和rustc的关系非常混乱,至少我能澄清一点。

你可以看到我的失败多于成功。找到性能赢家比过去困难得多。很多低垂的果实都被摘下来了,我的成功率也下降了。在usualbenchmarks上运行通常的分析器(并且只测量每个基准的最终板条箱,而不是整个合成图)比以前效率更低。

幸运的是,有一条前进的道路。lqd最近开始全职研究编译器性能,他做了一个大型的数据收集练习,在近800个最受欢迎的板条箱上运行了各种分析器。伊奥。这包括板条箱内部和跨项目测量。与benchmarksuite相比,这些结果让我们能够深入了解编译器在更大范围的真实代码中的性能,benchmarksuite有46个基准,其中只有一半来自真实世界。

编译器的某些部分对于某些板条箱来说是热门的,但这些在现有的基准测试中没有显示出来。宏解析是最极端的例子,看起来很可能是可以优化的。

某些板条箱被广泛使用且编译速度较慢,例如syn/quote/proc-macro2。可以改进吗?

我们的基准套件有许多3或4年历史的流行板条箱版本。我们应该更新它们,并可能添加/删除一些。

该分析为2022年的编译器性能工作提供了路线图。我昨天刚刚完成了分析草案和路线图文件,但它们已经取得了成果…

#93984:该PR为大位集引入了一种优化的表示法,这大大降低了少数板条箱的峰值内存要求(最多降低60%!),而且还避免了大量的内存复制,速度最高可达14%。令人高兴的是,这修复了自2018年推出“新”借阅检查器以来的最终卓越性能退化!

#94316:该PR优化了包含转义符的字符串文本的处理,在少数流行的板条箱上最多可获得7%的胜利。

从2021年11月11日到2022年02月25日,rustc基准套件的结果有303项改进,其中许多改进超过了10%,只有21项回归,如下截图总结。

对于rustc开发人员来说,还有一个很好的结果,就是rustc引导时间减少了10%。

在这3.5个月的时间里,这是一个健康的结果。这要归功于许多人的努力,并延续了绩效改进的长期趋势。