-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split symbol interner into static unsynchronized and dynamic synchronized parts #79425
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @lcnr (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
@bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit 1b87f079d416da1754abbd3b833e132aff5d0c7e with merge 84086bee5c514f7e2d2836aa88625bd50be1108c... |
@Mark-Simulacrum CI isn't quite passing yet; I was going to queue it as soon as CI passed. |
Just to note, there was a PR in this area with similar goals but different approach (packing short strings into a pointer). It wasn't merged in the end, but I thought it's worth mentioning. |
The try build failed (Option 'document-private-items' given more than once), FWIW, so perf won't run until that finishes successfully - the error is pretty odd, feels like maybe an implementation bug? |
#74554 wasn't merged because now we access the string representation of |
cc #73936 |
Symbol
s known at compile time
Symbol
s known at compile time
@sivadeilra |
First impressions:
|
cc @nnethercote |
For initial PRs I'd suggest:
This way we get all optimizations associated with
while keeping status quo in other aspects like |
This comment has been minimized.
This comment has been minimized.
e1fe2c0
to
f393eeb
Compare
I'll try to do some experiments with single-threaded performance on our standard benchmark in #80420. |
…sper rustc_span: Remove `Symbol::with` A subset of rust-lang#79425 that is a pure refactoring.
Ok, I think I know how to mitigate the regressions.
Comments:
|
@sivadeilra Ping from triage can you please address the merge conflict and post the status of this PR? |
Sure, will do. |
This improves performance of Symbol interning in several ways. The main motivation of this work is to prepare rustc for efficient parallel builds. The Symbol lookup table (mapping from strings to Symbol numbers) is now split into two separate tables: a static table and a dynamic table. The static table contains strings that are known to rustc, including all keywords and all `sym::foo` symbols. The dynamic table contains strings that rustc discovers while compiling, such as "my_super_obscure_function_name". Since the static table is known at compile time (that is, when rustc itself is being compiled), this table can be stored entirely in static data structures. We use the `phf` crate to generate this table; `phf` generates perfect hash functions. This allows rustc to perform Symbol lookups for static symbols without any multithreaded synchronization, or accessing any dynamic data whatsoever. I measured the percentage of static symbol lookups in many common Rust crates, including rust/compiler, rust/library, servo, rand, quote, syn, rust-analyzer, rayon, and rsvg. Among these crates, between 35% and 55% of all symbol lookups were resolved using the static lookup table.
a4a2fc9
to
6fa8898
Compare
The job Click to see the possible cause of the failure (guessed by this bot)
|
I think this design direction has merit, but it currently has one cost that is not acceptable. For single-threaded execution, it does penalize symbol lookups, because for many symbols it will query two hash tables, not just one. This cost could be reduced somewhat, but it's an inherent part of the design, so it can't be eliminated. Since one of the big sources of symbol lookups is importing metadata from dependent crates, I've been planning on doing an experiment, where we serialize symbols differently depending on whether they are "static" (known) or dynamic. For static symbols, we can simply write the symbol index, and we don't even need to write the string. During deserialization, we would simply use the symbol index, without any need to check any interning tables. I think it's possible that this would have a measurable performance benefit, and that the benefit might outweigh the cost of the double-lookup. @JohnCSimon, would you prefer that I abandon this PR, or change it to "draft", while I work on that experiment? It seems that this PR cannot be accepted in its current form, which I think is fine. Either that, or I could use |
@sivadeilra i would recommend closing this, working on the experiment and based on that you can reopen or create a new PR with these changes. Since the experiment will take some it would ensure that the PR doesnt stay open and rot with conflicts |
@Dylan-DPC Agreed. Closing this now. |
Draft PR for investigation of improving Symbol lookups
I've been working on understanding parallelism in Rust, and I noticed one opportunity for improvement. That's in how we handle interning strings as Symbols. I decided to avoid placing all "static" symbols (symbols known at compile time) in the Interner table, and instead to just assign them static indices.
The advantage of this is that you can avoid taking a lock for resolution of static symbols. I measured, and for many Rust crates, the number of symbol lookups that can be resolved statically is between 45% and 75%. So, this could significantly reduce the amount of lock contention in Symbol::intern, if/when we ever get the compiler moved to parallel builds.
I've run ./x.py test src/tests/ui, and everything passes. But there's still some cleanup left to do, which is why I'm creating this as a draft PR.