I love Rust and I love optimization. Rust helps me optimize by letting me write code that is both fast and nice. But the tools you need to write Rust code (cargo check, cargo build, cargo clippy) can be noticeably slow. While I love low-level optimizations, like using SIMD, I’m obsessed with the idea of engineering performance into a large project like Rust. I think Rust deserves significant attention to its build speed, to make it more accessible and to save energy. While there are plenty of talented people who care about build speed and are working to improve it, I want to take a somewhat unique approach.
I hypothesize that Rust compilation can be optimized significantly in ways that have not yet been explored. Specifically, I think changes to the interfaces between components — the APIs and data structures through which major parts of the compiler communicate with each other — can be designed differently to unlock new optimizations. This can mean a variety of things: changing control flow (parallelism, internal vs. external iteration), batching operations, specializing for frequent cases, and reorganizing data structures (e.g. struct-of-arrays). I’m not the first to think of these, of course: there are good reasons these changes have not been explored…
The optimizations I want to perform would require large-scale refactors of the Rust compiler, and this is just really really hard. The codebase is constantly in churn (because many people are working on it) and it has strict stability requirements. Large refactors are likely to stall other development and slowly succumb to a thousand paper cuts. Their benefits can only be measured after they are done, so it’s incredibly hard to justify doing them at all. But I have a workaround for this: I’m build a Rust compiler from the ground up, Krabby, so that I can explore architectural changes, iterate on designs, and quantify the value of these optimizations.
So, what is my approach here?
I’m going to work my way through each component of the Rust compiler, in order. There are some cross-cutting concerns, like the query system, which need to be considered; regardless, my focus for the next year is everything up to (path-based) name resolution.
For each component, I’m going to dive into
rustc’s implementation of it and try to optimize things there. As my mental model of the component gets better, I’ll collect ideas for architectural optimizations.Then, I will implement the component in Krabby (often porting over code I just optimized in
rustc) and try out the architectural optimizations I’m excited about. I’ll iterate on my designs until they are sufficiently easy to use; then, I’ll evaluate their performance characteristics.I’ll share what I find so other Rust developers can reference them to motivate making the necessary refactors in
rustc. I’ll continue developing Krabby on the side as a Rust compiler in its own right.
This work is being supported by my employer, NLnet Labs, as well as the RustNL foundation. Thanks to them, I get paid to work on Krabby and rustc for one day a week!
If you find this project interesting, you can help out! I want to flesh out Krabby to be something useful on its own, and if you’re interested in compilers and optimization you can contribute to it. Come have a chat on Zulip, send me an e-mail, or look at open issues. The code is hosted on Codeberg.
devlog
I’m writing about the ideas I have and the steps I’m taking in an informal devlog. Hopefully you’ll see a new post here every few weeks.