rustc_monomorphize: shard volatile generic CGU buckets to reduce incremental invalidation scope - #162692
rustc_monomorphize: shard volatile generic CGU buckets to reduce incremental invalidation scope#162692Trigodil wants to merge 6 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
β¦emental invalidation scope
b2d8f24 to
cfca780
Compare
This comment has been minimized.
This comment has been minimized.
|
Let's try this out. @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
rustc_monomorphize: shard volatile generic CGU buckets to reduce incremental invalidation scope
|
@bors try cancel |
|
Try build cancelled. Cancelled workflows: Hint: if you want to run another try build, you do not need to manually cancel the previous one. Just run |
Got it Co-authored-by: MatyΓ‘Ε‘ Racek <panstromek@seznam.cz>
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
rustc_monomorphize: shard volatile generic CGU buckets to reduce incremental invalidation scope
This comment has been minimized.
This comment has been minimized.
|
You can ignore tidy for experiments like this, it won't fail the |
Gotcha, its just really annoying for me when one fails |
This comment has been minimized.
This comment has been minimized.
|
It seems that forcing this on unconditionally breaks the tests, since they assert exact CGU names (e.g. local_generic.volatile) and now get a .shard0XX suffix appended everywhere |
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (6c4e7b9): comparison URL. Overall result: ββ regressions and improvements - please read:Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. Next, please: If you can, justify the regressions found in this try perf run in writing along with @bors rollup=never rustc-perf Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 2.4%, secondary 2.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 82.8%, secondary 63.6%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 32.7%, secondary 42.8%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 497.802s -> 494.017s (-0.76%) |
This comment has been minimized.
This comment has been minimized.
|
The results are quite negative, so now the question is how much time you want to sink into figuring this out. There might be something to gain here, because some results are green, but I suspect it's gonna be a pretty uphill battle. This area is a bit of a tarpit, so be warned. I can help with interpreting the results if you have some questions. If you decide to keep working on this to the point of landing something, keep in mind that this PR will probably interact with the LLM policy: https://forge.rust-lang.org/policies/llm-usage.html, so you should familiarize yourself with it and make sure you follow that when interacting with people here. |
|
I have implemented a fix, so hopefully it works, and yes, I am aware of the LLM policy of rust. |
|
Thanks for the pull request, and welcome! The Rust Project has assigned @folkertdev (or someone else) to review your changes, you should hear from them (or someone else) within the next two weeks. Please see the contribution instructions and our LLM policy for more information. Why was this reviewer chosen?The reviewer was selected based on:
|
|
To be clear, since this is not a draft anymore - I don't think we should land this atm. We can re-measure this but I kinda doubt the regression goes away and adding new unstable flag for this doesn't sound sufficiently motivated to me (maybe it also needs MCP, but I'm not sure atm). |
|
Yeah I think we can re-measure this one more time, if the regression isn't fixed, I think something else is wrong. Either way if it still regresses I think it is better off closing this pull request |
|
So, I guess @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
rustc_monomorphize: shard volatile generic CGU buckets to reduce incremental invalidation scope
This comment has been minimized.
This comment has been minimized.
|
Wait, it's still disabled by default, isn't it? |
|
Finished benchmarking commit (70399b2): comparison URL. Overall result: β improvements - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 1.0%, secondary -0.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 2.2%, secondary 4.6%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 494.003s -> 495.931s (0.39%) |
|
Hmmm, the improvement seems to be lower than my benchmarks and system, thoughts? I think the gains only kick in when you have a crate with massive generic monomorphization volume like polars |
|
Let me see if I can optimize this even more |
|
The last benchmark run doesn't have
If you go to comparison url, you can click every benchmark and it will give you some detailed information about it and link to the source code. We run incremental, those are the In your case, you want to pay attention
In general, I recommend reading the profiling chapters in the dev guide, running the suite through |
|
If you want to benchmark the updated version, you may want to temporarily re-add the commit that force-enabled this (deleting the conditional), solely to ensure that it's used during the perf run. I'd be interested in seeing how much impact this has. Whether or not it gets used in this exact form, it'd be interesting to know whether the technique is a win. |
View all comments
Summary
The current CGU partitioner assigns every monomorphized instance of a generic
function from the same module into a single "volatile" bucket, keyed on
(module_def_id, volatile). This means editing the body of any instantiationinvalidates the entire bucket -- every other instantiation in that module gets
re-emitted on the next incremental build, even ones that share no code with the
change.
This PR adds
-Z fine-grained-generic-cgus, which shards each volatile bucketinto a bounded number of sub-buckets by hashing the instantiation's fully-mangled
symbol name. An edit to one instantiation's code path now only invalidates the
~1/shard_count of instantiations that hash into the same shard.
Approach
Shard count is derived from
-C codegen-units, floored at the host's availableparallelism and clamped to [4, 128]. This keeps the total CGU count in the same
ballpark as a normal build while ensuring the codegen backend always has enough
independent units to keep every core busy.
Unbounded splitting (one CGU per instantiation) was tested first and regresses
heavily on real crates:
merge_codegen_unitsis intentionally skipped inincremental mode, so hundreds of tiny object files pile up with no recombination,
and link cost dominates. Bounded sharding avoids this entirely.
Benchmarks (polars-core, ChunkedArray)
-Z threads=4Tested on
polars-corewhich has high monomorphization volume(
ChunkedArray<T>instantiations survivemerge_codegen_unitsand make thevolatile bucket expensive to invalidate). Methodology uses a body-edit approach
by item content, not file bytes.
Notes
Disclosure
Claude Sonnet 4.6 was used to speed up compiler research and to rule out dead ends in the methodology used.