惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Troy Hunt's Blog
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - Franky
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Martin Fowler
Martin Fowler
V
Visual Studio Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
云风的 BLOG
云风的 BLOG
G
Google Developers Blog
WordPress大学
WordPress大学
腾讯CDC
J
Java Code Geeks
T
The Blog of Author Tim Ferriss
博客园 - 司徒正美
博客园 - 【当耐特】
小众软件
小众软件
Attack and Defense Labs
Attack and Defense Labs
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
罗磊的独立博客
Schneier on Security
Schneier on Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
O
OpenAI News
TaoSecurity Blog
TaoSecurity Blog
H
Heimdal Security Blog
Blog — PlanetScale
Blog — PlanetScale
Forbes - Security
Forbes - Security
B
Blog
I
InfoQ
D
DataBreaches.Net
月光博客
月光博客
T
Tenable Blog
S
Security Affairs
C
Check Point Blog
T
Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
www.infosecurity-magazine.com
www.infosecurity-magazine.com

Rust Blog

Security Advisory for Cargo (CVE-2026-5223) | Rust Blog Security Advisory for Cargo (CVE-2026-5222) | Rust Blog Project goals update — April 2026 (end of 2025H2) | Rust Blog Rust is participating in Outreachy | Rust Blog Raising the baseline for the `nvptx64-nvidia-cuda` target | Rust Blog Announcing Google Summer of Code 2026 selected projects | Rust Blog Announcing Rust 1.95.0 | Rust Blog docs.rs: building fewer targets by default | Rust Blog Changes to WebAssembly targets and handling undefined symbols | Rust Blog Announcing Rust 1.94.1 | Rust Blog Security advisory for Cargo | Rust Blog What we heard about Rust's challenges | Rust Blog Call for Testing: Build Dir Layout v2 | Rust Blog Announcing rustup 1.29.0 | Rust Blog Announcing Rust 1.94.0 | Rust Blog 2025 State of Rust Survey Results | Rust Blog Rust debugging survey 2026 | Rust Blog Update on the October 15, 2018 incident on crates.io Announcing Rust 1.29.2 Announcing Rust 1.29 Announcing Rust 1.28 What is Rust 2018? Announcing Rust 1.27.2 Announcing Rust 1.27.1 Security Advisory for rustdoc Announcing Rust 1.27 Announcing Rust 1.26.2 Announcing Rust 1.26.1 Rust turns three Announcing Rust 1.26 The Rust Team All Hands in Berlin: a Recap Increasing Rust’s Reach 2018 Announcing Rust 1.25 Rust's 2018 roadmap Announcing Rust 1.24.1 Announcing Rust 1.24 The 2018 Rust Event Lineup Announcing Rust 1.23 New Year's Rust: A Call for Community Blogposts Rust in 2017: what we achieved Announcing Rust 1.22 (and 1.22.1) Fearless Concurrency in Firefox Quantum Announcing Rust 1.21 impl Future for Rust Rust 2017 Survey Results Announcing Rust 1.20 Announcing Rust 1.19 The 2017 Rust Conference Lineup Rust's 2017 roadmap, six months in Increasing Rust’s Reach Announcing Rust 1.18 Two years of Rust The Rust Libz Blitz Launching the 2017 State of Rust Survey Announcing Rust 1.17 Announcing Rust 1.16 Rust's language ergonomics initiative Announcing Rust 1.15.1 Rust's 2017 roadmap Announcing Rust 1.15 Announcing Rust 1.14 Announcing the First Underhanded Rust Contest Announcing Rust 1.13 Announcing Rust 1.12.1 Announcing Rust 1.12 Incremental Compilation Announcing Rust 1.11 Shape of errors to come The 2016 Rust Conference Lineup Announcing Rust 1.10 State of Rust Survey 2016 Announcing Rust 1.9 One year of Rust Taking Rust everywhere with rustup Launching the 2016 State of Rust Survey Cargo: predictable dependency management Introducing MIR Announcing Rust 1.8 Announcing Rust 1.7 Announcing Rust 1.6 Announcing Rust 1.5 Announcing Rust 1.4 Announcing Rust 1.3 Rust in 2016 Announcing Rust 1.2 Rust 1.1 stable, the Community Subteam, and RustCamp Announcing Rust 1.0 Abstraction without overhead: traits in Rust Rust Once, Run Everywhere Mixing matching, mutation, and moves in Rust Fearless Concurrency with Rust Announcing Rust 1.0 Beta Announcing Rust 1.0.0.alpha.2 Rust 1.0: status report and final timeline Announcing Rust 1.0 Alpha Rust 1.0: Scheduling the trains Yehuda Katz and Steve Klabnik are joining the Rust Core Team Cargo: Rust's community crate host Stability as a Deliverable Road to Rust 1.0
Faster compilation with the parallel front-end in nightly
Nicholas Nethercote on behalf of The Parallel Rustc Working · 2023-11-09 · via Rust Blog

The Rust compiler's front-end can now use parallel execution to significantly reduce compile times. To try it, run the nightly compiler with the -Z threads=8 option. This feature is currently experimental, and we aim to ship it in the stable compiler in 2024.

Keep reading to learn why a parallel front-end is needed and how it works, or just skip ahead to the How to use it section.

Compile times and parallelism

Rust compile times are a perennial concern. The Compiler Performance Working Group has continually improved compiler performance for several years. For example, in the first 10 months of 2023, there were mean reductions in compile time of 13%, in peak memory use of 15%, and in binary size of 7%, as measured by our performance suite.

However, at this point the compiler has been heavily optimized and new improvements are hard to find. There is no low-hanging fruit remaining.

But there is one piece of large but high-hanging fruit: parallelism. Current Rust compiler users benefit from two kinds of parallelism, and the newly parallel front-end adds a third kind.

Existing interprocess parallelism

When you compile a Rust program, Cargo launches multiple rustc processes, compiling multiple crates in parallel. This works well. Try compiling a large Rust program with the -j1 flag to disable this parallelization and it will take a lot longer than normal.

You can visualise this parallelism if you build with Cargo's --timings flag, which produces a chart showing how the crates are compiled. The following image shows the timeline when building ripgrep on a machine with 28 virtual cores.

cargo build --timings output when compiling ripgrep

There are 60 horizontal lines, each one representing a distinct process. Their durations range from a fraction of a second to multiple seconds. Most of them are rustc, and the few orange ones are build scripts. The first twenty processes all start at the same time. This is possible because there are no dependencies between the relevant crates. But further down the graph, parallelism reduces as crate dependencies increase. Although the compiler can overlap compilation of dependent crates somewhat thanks to a feature called pipelined compilation, there is much less parallel execution happening towards the end of compilation, and this is typical for large Rust programs. Interprocess parallelism is not enough to take full advantage of many cores. For more speed, we need parallelism within each process.

Existing intraprocess parallelism: the back-end

The compiler is split into two halves: the front-end and the back-end.

The front-end does many things, including parsing, type checking, and borrow checking. Until this week, it could not use parallel execution.

The back-end performs code generation. It generates code in chunks called "codegen units" and then LLVM processes these in parallel. This is a form of coarse-grained parallelism.

We can visualize the difference between the serial front-end and the parallel back-end. The following image shows the output of a profiler called Samply measuring rustc as it does a release build of the final crate in Cargo. The image is superimposed with markers that indicate front-end and back-end execution.

Samply output when compiling Cargo, serial

Each horizontal line represents a thread. The main thread is labelled "rustc" and is shown at the bottom. It is busy for most of the execution. The other 16 threads are LLVM threads, labelled "opt cgu.00" through to "opt cgu.15". There are 16 threads because 16 is the default number of codegen units for a release build.

There are several things worth noting.

  • Front-end execution takes 10.2 seconds.
  • Back-end execution takes 6.2 seconds, and the LLVM threads are running for 5.9 seconds of that.
  • The parallel code generation is highly effective. Imagine if all those LLVM executed one after another!
  • Even though there are 16 LLVM threads, at no point are all 16 executing at the same time, despite this being run on a machine with 28 cores. (The peak is 14 or 15.) This is because the main thread translates its internal code representation (MIR) to LLVM's code representation (LLVM IR) in serial. This takes a brief period for each codegen unit, and explains the staircase shape on the left-hand side of the code generation threads. There is some room for improvement here.
  • The front-end is entirely serial. There is a lot of room for improvement here.

New intraprocess parallelism: the front-end

The front-end is now capable of parallel execution. It uses Rayon to perform compilation tasks using fine-grained parallelism. Many data structures are synchronized by mutexes and read-write locks, atomic types are used where appropriate, and many front-end operations are made parallel. The addition of parallelism was done by modifying a relatively small number of key points in the code. The vast majority of the front-end code did not need to be changed.

When the parallel front-end is enabled and configured to use eight threads, we get the following Samply profile when compiling the same example as before.

Samply output when compiling Cargo, parallel

Again, there are several things worth noting.

  • Front-end execution takes 5.9 seconds (down from 10.2 seconds).
  • Back-end execution takes 5.3 seconds (down from 6.2 seconds), and the LLVM threads are running for 4.9 seconds of that (down from 5.9 seconds).
  • There are seven additional threads labelled "rustc" operating in the front-end. The reduced front-end time shows they are reasonably effective, but the thread utilization is patchy, with the eight threads all having periods of inactivity. There is room for significant improvement here.
  • Eight of the LLVM threads start at the same time. This is because the eight "rustc" threads create the LLVM IR for eight codegen units in parallel. (For seven of those threads that is the only work they do in the back-end.) After that, the staircase effect returns because only one "rustc" thread does LLVM IR generation while seven or more LLVM threads are active. If the number of threads used by the front-end was changed to 16 the staircase shape would disappear entirely, though in this case the final execution time would barely change.

Putting it all together

Rust compilation has long benefited from interprocess parallelism, via Cargo, and from intraprocess parallelism in the back-end. It can now also benefit from intraprocess parallelism in the front-end.

You might wonder how interprocess parallelism and intraprocess parallelism interact. If we have 20 parallel rustc invocations and each one can have up to 16 threads running, could we end up with hundreds of threads on a machine with only tens of cores, resulting in inefficient execution as the OS tries its best to schedule them?

Fortunately no. The compiler uses the jobserver protocol to limit the number of threads it creates. If a lot of interprocess parallelism is occurring, intraprocess parallelism will be limited appropriately, and the number of threads will not exceed the number of cores.

How to use it

The nightly compiler is now shipping with the parallel front-end enabled. However, by default it runs in single-threaded mode and won't reduce compile times.

Keen users can opt into multi-threaded mode with the -Z threads option. For example:

$ RUSTFLAGS="-Z threads=8" cargo build --release

Alternatively, to opt in from a config.toml file (for one or more projects), add these lines:

[build]
rustflags = ["-Z", "threads=8"]

It may be surprising that single-threaded mode is the default. Why parallelize the front-end and then run it in single-threaded mode? The answer is simple: caution. This is a big change! The parallel front-end has a lot of new code. Single-threaded mode exercises most of the new code, but excludes the possibility of threading bugs such as deadlocks that can affect multi-threaded mode. Even in Rust, parallel programs are harder to write correctly than serial programs. For this reason the parallel front-end also won't be shipped in beta or stable releases for some time.

Performance effects

When the parallel front-end is run in single-threaded mode, compilation times are typically 0% to 2% slower than with the serial front-end. This should be barely noticeable.

When the parallel front-end is run in multi-threaded mode with -Z threads=8, our measurements on real-world code show that compile times can be reduced by up to 50%, though the effects vary widely and depend on the characteristics of the code and its build configuration. For example, dev builds are likely to see bigger improvements than release builds because release builds usually spend more time doing optimizations in the back-end. A small number of cases compile more slowly in multi-threaded mode than single-threaded mode. These are mostly tiny programs that already compile quickly.

We recommend eight threads because this is the configuration we have tested the most and it is known to give good results. Values lower than eight will see smaller benefits, but are appropriate if your hardware has fewer than eight cores. Values greater than eight will give diminishing returns and may even give worse performance.

If a 50% improvement seems low when going from one to eight threads, recall from the explanation above that the front-end only accounts for part of compile times, and the back-end is already parallel. You can't beat Amdahl's Law.

Memory usage can increase significantly in multi-threaded mode. We have seen increases of up to 35%. This is unsurprising given that various parts of compilation, each of which requires a certain amount of memory, are now executing in parallel.

Correctness

Reliability in single-threaded mode should be high.

In multi-threaded mode there are some known bugs, including deadlocks. If compilation hangs, you have probably hit one of them.

The binaries produced by the compiler are expected to be the same no matter which front-end is being used. Any differences will be considered a bug.

Feedback

If you have any problems with the parallel front-end, please check the issues marked with the "WG-compiler-parallel" label. If your problem does not match any of the existing issues, please file a new issue.

For more general feedback, please start a discussion on the wg-parallel-rustc Zulip channel. We are particularly interested to hear the performance effects on the code you care about.

Future work

We are working to improve the performance of the parallel front-end. As the graphs above showed, there is room to improve the utilization of the threads in the front-end. We are also ironing out the remaining bugs in multi-threaded mode.

We aim to stabilize the -Z threads option and ship the parallel front-end running by default in multi-threaded mode on stable releases in 2024.

Acknowledgments

The parallel front-end has been under development for a long time. It was started by @Zoxc, who also did most of the work for several years. After a period of inactivity, the project was revived this year by @SparrowLii, who led the effort to get it shipped. Other members of the Parallel Rustc Working Group have also been involved with reviews and other activities. Many thanks to everyone involved.