performance regression with -Znext-solver=globally
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
The new solver struggles more than the old one with (somewhat pathologically) large bodies, which happen in generated code quite a bit, I imagine. This is readily reproduced with:
// lib.rs — one function, N repetitions of the push line
pub fn big() {
let mut v = Vec::new();
v.push(Default::default());
// ... repeat N times ...
v.push(0u8);
}
To create the test cases:
python3 -c "
n = 4000
print('pub fn big() {'); print(' let mut v = Vec::new();')
print(' v.push(Default::default());\n' * n, end='')
print(' v.push(0u8);'); print('}')" > lib.rs
Run (typeck only, no codegen):
rustc +nightly --crate-type=lib --edition=2024 --emit=metadata --out-dir /tmp/out lib.rs
rustc +nightly --crate-type=lib --edition=2024 --emit=metadata --out-dir /tmp/out -Znext-solver=globally lib.rs
Measurements (wall clock)
| N (pushes) | old solver | next solver | next/old |
|---|---|---|---|
| 500 | 0.06s | 0.74s | 12× |
| 1,000 | 0.15s | 2.88s | 19× |
| 2,000 | 0.47s | 11.06s | 24× |
| 4,000 | 1.76s | 46.85s | 27× |
| 8,000 | 6.97s | 216.27s | 31× |
| 16,000 | 28.35s | (not measured) | — |
Both are clearly non-linear in behavior, due to the O(n) passes x O(n) pending obligations, but the new solver has a much higher constant factor, it seems. The work done in #158249 has made each handling of a stalled obligation cheaper, but did not remove the scan. My friendly neighborhood AI points to FulfillmentCtxt::try_evaluate_obligations gathering work with drain_pending(|_, _| true) in compiler/rustc_trait_selection/src/solve/fulfill.rs.
The following might well be related:
- rust-lang/rust#131411 (cranelift-codegen, ISLE-generated functions, 10×, open and undiagnosed)
- rust-lang/trait-system-refactor-initiative#228 (wg-grammar, closed as "acceptable" after constant-factor fast-path work)
- rust-lang/trait-system-refactor-initiative#254 (crater perf triage)
I've run into this in rust-analyzer, which shares this code, its inference makes more fulfillment passes per body.
Meta
rustc 1.99.0-nightly (89c61a754 2026-07-23)
Disclosure: the investigation and benchmarking was supported by AI
@rustbot label +I-compiletime +WG-trait-system-refactor
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the supplied generated lib.rs reproducer and the two rustc commands, then inspect compiler/rustc_trait_selection/src/solve/fulfill.rs, especially try_evaluate_obligations and drain_pending. Compare timings across the listed push counts and trace the pending-obligation work; done means identifying and addressing the next-solver regression without changing the reproducer's expected behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100