How to speed up the Rust compiler in July 2026

How to speed up the Rust compiler in July 2026

如何在 2026 年 7 月加速 Rust 编译器

My last post on the Rust compiler’s performance was in December 2025. Let’s see what has happened since then. 我上一篇关于 Rust 编译器性能的文章是在 2025 年 12 月发布的。让我们看看从那时起发生了什么。

Overall progress

总体进展

The measurements for the period 2025-12-03 to 2026-07-29 can be seen here. The mean wall-time reduction was a healthy 5.59%. Around half of this was due to some huge recent improvements in rustdoc, which saw a mean wall-time reduction of 37.92%! With the rustdoc changes excluded, the mean wall-time change was 2.90%, which is still a good result. There were also some major improvements to the speed of Clippy, which isn’t currently measured by rustc-perf on CI. (More about that below.) 2025 年 12 月 3 日至 2026 年 7 月 29 日期间的测量结果可以在这里查看。平均挂钟时间(wall-time)减少了 5.59%,这是一个相当不错的成绩。其中约一半的功劳归功于近期 rustdoc 的巨大改进,其平均挂钟时间减少了 37.92%!如果排除 rustdoc 的变动,平均挂钟时间减少了 2.90%,这依然是一个很好的结果。此外,Clippy 的速度也有显著提升,尽管目前 rustc-perf 的 CI 尚未对其进行测量。(下文将详细介绍。)

rustdoc

rustdoc

#159623, #159721, #159779, #159854: In these PRs, Noah Lev greatly reduced the amount of work done when processing impls. I won’t pretend to understand what he did in any more detail than that (see here for some background) but I do know it resulted in many double- and single-digit percentage reductions in wall-times. Guillaume Gomez said “all of that because someone encountered a weird bug when using rustdoc”. #159623, #159721, #159779, #159854:在这些 PR 中,Noah Lev 大幅减少了处理 impl 时的工作量。我不会假装自己比这更了解他做了什么(背景信息见此处),但我知道这使得挂钟时间出现了多次两位数和个位数的百分比下降。Guillaume Gomez 说:“这一切都是因为有人在使用 rustdoc 时遇到了一个奇怪的 bug。”

#159091: In this PR Jakub Beránek added rustdoc benchmarks to the PGO training set, which lets rustdoc benefit more from PGO. This gave a mean 2.85% reduction in wall-time across all the rustdoc benchmarks, with the largest reduction exceeding 6%. PGO is fiddly to set up but it can really make a difference, and the training set matters. #159091:在此 PR 中,Jakub Beránek 将 rustdoc 基准测试添加到了 PGO 训练集中,这使得 rustdoc 能从 PGO 中获益更多。这使得所有 rustdoc 基准测试的平均挂钟时间减少了 2.85%,最大降幅超过了 6%。PGO 的设置虽然繁琐,但确实能带来显著差异,且训练集至关重要。

#157179: In this PR I changed the way rustdoc sorts impls. Previously it was sorting long generated HTML strings containing impl names; now it uses a much shorter text representation of the impl name as the sort key. This reduced instruction counts across multiple benchmarks, in the best case by more than 6%. The combined effect of these improvements can be seen in the following graph of the relative wall-time of all the rustdoc benchmarks. That’s a 28% reduction! #157179:在此 PR 中,我改变了 rustdoc 对 impl 进行排序的方式。之前它是对包含 impl 名称的长生成 HTML 字符串进行排序;现在它使用 impl 名称的更短文本表示作为排序键。这减少了多个基准测试中的指令计数,最佳情况下减少了超过 6%。这些改进的综合效果可以从下图中所有 rustdoc 基准测试的相对挂钟时间看出。这可是 28% 的降幅!

#2515: On a different note, in this PR Jakub enabled rustdoc-json benchmarking on rustc-perf. This will be helpful for the speed of tools that use rustdoc’s JSON output, such as cargo-semver-checks. #2515:另外,Jakub 在此 PR 中启用了 rustc-perf 上的 rustdoc-json 基准测试。这将有助于提升使用 rustdoc JSON 输出的工具(如 cargo-semver-checks)的速度。

Clippy

Clippy

#17124, #17132: In these two PRs, xmakro made some huge speed-ups to Clippy. Clippy consists of hundreds of separate lints, each of which can implement one or more of a few dozen visitor methods: check_item, check_stmt, check_expr, etc. Clippy traverses the AST and HIR and for each node it calls the appropriate check_foo method for every lint on that node. Each call is a virtual dispatch. Critically, most of these calls are no-ops because most lints only implement a small number of check_foo methods (often just one). In these PRs, xmakro found a way to combine the passes so that the empty check_foo methods (i.e. the vast majority) are not called. #17124, #17132:在这两个 PR 中,xmakro 对 Clippy 进行了巨大的速度优化。Clippy 由数百个独立的 lint 组成,每个 lint 可以实现几十个访问者方法中的一个或多个:check_item、check_stmt、check_expr 等。Clippy 遍历 AST 和 HIR,并为每个节点调用该节点上每个 lint 对应的 check_foo 方法。每次调用都是一次虚函数分发(virtual dispatch)。关键在于,大多数调用都是空操作,因为大多数 lint 只实现少数几个 check_foo 方法(通常只有一个)。在这些 PR 中,xmakro 找到了一种合并遍历的方法,使得空的 check_foo 方法(即绝大多数)不会被调用。

Around the same time I was investigating the exact same issue, and I came up with a slightly different solution in #157762. My solution was functionally equivalent but the code changes were less elegant and more invasive than xmakro’s. The PR didn’t merge, but I was able to get more detailed measurements: in most cases this reduced Clippy’s runtime by 10-30%! Branch mispredictions were reduced by 20-80% on real-world examples and by 97% on one stress test. The cost of virtual dispatch adds up if you do it a lot. Even though I’ve been working on Rust compiler performance for ten years, this was the first time I tried to optimize Clippy. I found a major performance problem and fixed it, only to find someone else had beaten me to it by a few days. I’m not sad because the better solution was merged, but I am still surprised—what are the chances of that? 大约在同一时间,我正在调查完全相同的问题,并在 #157762 中提出了一个略有不同的解决方案。我的方案在功能上是等效的,但代码改动不如 xmakro 的优雅且更具侵入性。该 PR 没有被合并,但我得以获得了更详细的测量数据:在大多数情况下,这使 Clippy 的运行时间减少了 10-30%!在真实案例中,分支预测错误减少了 20-80%,在一次压力测试中减少了 97%。如果你频繁使用虚函数分发,其开销会累积起来。尽管我从事 Rust 编译器性能优化工作已有十年,但这还是我第一次尝试优化 Clippy。我发现了一个重大的性能问题并修复了它,结果发现别人比我早几天就做到了。我并不难过,因为更好的方案被合并了,但我仍然感到惊讶——这种巧合的概率有多大呢?

Incremental compilation

增量编译

We saw a number of minor improvements to incremental compilation. 我们看到了增量编译方面的一些小改进。

#153122: In this PR Zalathar improved how incremental compilation promotes disk-cached values into memory, reducing instruction counts on many benchmarks, in the best case by 6%. #153122:在此 PR 中,Zalathar 改进了增量编译将磁盘缓存值提升到内存中的方式,减少了许多基准测试中的指令计数,最佳情况下减少了 6%。

#153521: This PR was another tweak to incremental compilation by Zalathar, reducing instruction counts on many benchmarks, in the best cases by more than 2%. #153521:这是 Zalathar 对增量编译的另一次调整,减少了许多基准测试中的指令计数,最佳情况下减少了超过 2%。

#154304: In this PR zetanumbers adjusted how the typeck query works, for instruction count reductions across multiple benchmarks, in the best case by 6%. #154304:在此 PR 中,zetanumbers 调整了 typeck 查询的工作方式,从而在多个基准测试中减少了指令计数,最佳情况下减少了 6%。

#157781: In this PR xmakro tweaked incremental compilation for instruction count reductions across many benchmarks, in the best case by 5%. #157781:在此 PR 中,xmakro 调整了增量编译,在许多基准测试中减少了指令计数,最佳情况下减少了 5%。

#158794: In this PR xmakro improved dep graph read deduplication for instruction count reductions across multiple benchmarks, in the best case by 10%. #158794:在此 PR 中,xmakro 改进了依赖图读取去重,在多个基准测试中减少了指令计数,最佳情况下减少了 10%。

#159115: In this PR xmakro again improved dep graph read deduplication for instruction count reductions across many benchmarks, in the best case by 6%. #159115:在此 PR 中,xmakro 再次改进了依赖图读取去重,在许多基准测试中减少了指令计数,最佳情况下减少了 6%。

New trait solver

新的 trait 解析器

A lot of work is underway to get the new trait solver ready for release. This includes performance work. There is a lot going on and I’m not aware of most of it, but this Zulip thread is a good place to read if you are interested in learning more or helping. The following image shows the progress on one of the new solver benchmarks. That’s right: the wall-time on this benchmark has dropped from 27 seconds to less than one second over the past three months. 为了让新的 trait 解析器准备好发布,目前正在进行大量工作,其中包括性能优化。进展非常多,我并不了解其中的大部分,但如果你有兴趣了解更多或提供帮助,这个 Zulip 讨论串是一个很好的阅读起点。下图展示了其中一个新解析器基准测试的进展。没错:在过去三个月里,该基准测试的挂钟时间从 27 秒下降到了不到 1 秒。

#160005: I will mention this one because it’s fun. lcnr pointed at a couple of crates where the new trait solver was causing very large slowdowns. I used Cachegrind to profile rustc compiling them and found that almost half the time was spent in memcpy! This is very unusual, but when it happens DHAT’s copy profiling is unbelievably useful. There was a hot vector with an element type that was 136 bytes in size. LLVM uses memcpy (instead of generated instructions) to move around any value with a size greater than 128 bytes. In this PR I (a) avoided 2/3 of the moves, and (b) shrank the type down to 104 bytes so that memcpy wasn’t used for the remaining moves. This reduced wall-times for the two worst crates by 40%. #160005:我要提一下这个,因为它很有趣。lcnr 指出有几个 crate 在使用新的 trait 解析器时出现了严重的性能下降。我使用 Cachegrind 对编译这些 crate 的 rustc 进行了分析,发现几乎一半的时间都花在了 memcpy 上!这非常罕见,但一旦发生,DHAT 的拷贝分析工具就极其有用。有一个热点向量(vector),其元素类型大小为 136 字节。LLVM 会使用 memcpy(而不是生成的指令)来移动任何大于 128 字节的值。在此 PR 中,我 (a) 避免了 2/3 的移动,并且 (b) 将类型缩小到 104 字节,从而使剩余的移动不再使用 memcpy。这使得这两个最慢的 crate 的挂钟时间减少了 40%。

New contributors

新贡献者

There has been a welcome uptick in the amount of performance work being done recently and I want to highlight two newcomers. The first is xmakro, who was mentioned four times above. The sec… 最近性能优化工作的数量有了令人欣喜的增长,我想特别介绍两位新成员。第一位是 xmakro,他在上文中被提到了四次。第二位是…