Skip to content

Resolver: Parallelize the import resolution loop - #158845

Open
LorrensP-2158466 wants to merge 9 commits into
rust-lang:mainfrom
LorrensP-2158466:parallel-import-resolution
Open

Resolver: Parallelize the import resolution loop#158845
LorrensP-2158466 wants to merge 9 commits into
rust-lang:mainfrom
LorrensP-2158466:parallel-import-resolution

Conversation

@LorrensP-2158466

@LorrensP-2158466 LorrensP-2158466 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

View all comments

Follow up of #159440. This pr implements the parallel part of par_for_each_slice. And implements DynSend and DynSync for RefOrMut and CmCell to make the call to par_for_each_slice compile.

This is the bare minimum to make the parallel loop work and is not at all optimized, this will follow :).

r? @petrochenkov

@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 6, 2026
@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jul 6, 2026
@LorrensP-2158466

Copy link
Copy Markdown
Contributor Author

Lets see what CI says.

I have tried to add comments to changes to show my thought process behind them, but i'll make another pass here as well to be sure.

Comment thread compiler/rustc_data_structures/src/sync/parallel.rs Outdated
Comment thread compiler/rustc_resolve/src/build_reduced_graph.rs Outdated
Comment thread compiler/rustc_resolve/src/imports.rs Outdated
Comment thread compiler/rustc_resolve/src/imports.rs
Comment thread compiler/rustc_resolve/src/imports.rs Outdated
Comment thread compiler/rustc_resolve/src/imports.rs Outdated
@rust-log-analyzer

This comment has been minimized.

Comment thread compiler/rustc_resolve/src/lib.rs Outdated
Comment thread compiler/rustc_resolve/src/lib.rs
Comment thread compiler/rustc_resolve/src/lib.rs Outdated
@rust-log-analyzer

This comment has been minimized.

@LorrensP-2158466
LorrensP-2158466 force-pushed the parallel-import-resolution branch from 17bd1cb to 9aa1069 Compare July 6, 2026 10:48
@rust-log-analyzer

This comment has been minimized.

@LorrensP-2158466
LorrensP-2158466 force-pushed the parallel-import-resolution branch from 9aa1069 to a45ba86 Compare July 6, 2026 11:31
@petrochenkov petrochenkov added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 6, 2026
@petrochenkov

Copy link
Copy Markdown
Contributor

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 6, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 6, 2026
…r=<try>

Resolver: Parallelize the import resolution loop
Comment thread compiler/rustc_data_structures/src/sync.rs Outdated
Comment thread compiler/rustc_interface/src/passes.rs Outdated
Comment thread compiler/rustc_resolve/src/lib.rs Outdated
Comment thread compiler/rustc_resolve/src/lib.rs
Comment thread compiler/rustc_resolve/src/lib.rs
Comment thread compiler/rustc_resolve/src/lib.rs Outdated
Comment thread compiler/rustc_resolve/src/lib.rs Outdated
Comment thread compiler/rustc_resolve/src/build_reduced_graph.rs Outdated
Comment thread compiler/rustc_resolve/src/build_reduced_graph.rs
Comment thread compiler/rustc_resolve/src/build_reduced_graph.rs Outdated
@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 6, 2026
@rust-bors

rust-bors Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 3df1fed (3df1fed3aaf1081aa59cfe2228eed289a2ef744e)
Base parent: 3c00c96 (3c00c96d3af4d5b5e101e56cc161a608b21366ee)

@rust-timer

This comment has been minimized.

@petrochenkov

petrochenkov commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

I meant that we need read access during speculative resolution and interior mutability elsewhere for things wrapped in CmRefCell.

Yes, but it doesn't mean the data in CmRefCell needs to be additionally protected by a mutex or rwlock.
It is already protected by the assert_speculative flag (which needs to be atomic, most likely).
I guess the main question is how to express it in Rust terms, without plaguing the whole resolver with unsafe.

@LorrensP-2158466

LorrensP-2158466 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

After a lot of brainstorming I came up with an API like this (not detailed though):

/// A cell that supports:
/// - mutable access in normal resolution (single-threaded)
/// - shared access in speculative resolution (multi-threaded)
struct CmRefCell<T> {
    // mimic RefCell but with some tricks.
}

enum CmBorrow<'a, T> {
    /// Normal resolution: RefCell-like borrow tracking
    Normal(Ref<'a, T>),

    /// Speculative resolution: plain shared reference
    Speculative(&'a T),
}

impl<T> CmRefCell<T> {
    fn borrow(&self, resolver: &CmResolver<'_, '_, '_>) -> CmBorrow<'_, T> {
        if resolver.is_speculative() {
            CmBorrow::Speculative(/* shared access */)
        } else {
            CmBorrow::Normal(/* RefCell borrow */)
        }
    }

    fn borrow_mut(&self, resolver: &CmResolver<'_, '_, '_>) -> RefMut<'_, T> {
        assert!(!resolver.is_speculative());
        /* mutable access */
    }
}

Which has no synchronization because we do not need to mutate anything during speculative resolution, but we can still read. During non-speculative resolution we have the semantics we always had and Deref to &T for CmBorrow should be "zero-cost" if the &T are stored in the same place in both variants (otherwise a union?)

I have a feeling this could work, is this something that you were thinking of as well? Though unsafe is required here.

@LorrensP-2158466

Copy link
Copy Markdown
Contributor Author

I am currently merging it over to a seperate crate to check with miri, but in the case you want to take a look and maybe do a perf run, @rustbot ready.

Note it is not done, i am still working on it.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 25, 2026
@LorrensP-2158466
LorrensP-2158466 force-pushed the parallel-import-resolution branch from 67b5d60 to c63be60 Compare July 25, 2026 20:38
…n. When in speculative resolution, only shared borrows are allowed.

An actual conditional `RefCell`.
@LorrensP-2158466
LorrensP-2158466 force-pushed the parallel-import-resolution branch from c63be60 to c25cae6 Compare July 25, 2026 22:26
@petrochenkov

Copy link
Copy Markdown
Contributor

is this something that you were thinking of as well?

Same as #158845 (comment), I cannot answer without repeating the work and trying to implement in myself, but the high-level design seems plausible.

Comment thread compiler/rustc_resolve/src/lib.rs Outdated
Comment thread compiler/rustc_resolve/src/lib.rs Outdated
Comment thread compiler/rustc_resolve/src/lib.rs Outdated
@petrochenkov

Copy link
Copy Markdown
Contributor

I've finally read the safety comments in detail, they look more convincing now.
@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 27, 2026
@LorrensP-2158466

Copy link
Copy Markdown
Contributor Author

I've finally read the safety comments in detail, they look more convincing now.

I'll think that I will extend them a bit and add a comment to the ref_mut module as to why we want these (weird) data structures.

@LorrensP-2158466

Copy link
Copy Markdown
Contributor Author

Updated the comments and used RefCell instead of the manual impl, @rustbot ready.

Comment on lines +3020 to 3027
// Soundness depends entirely on proper usage of the `assert_speculative` field in the
// `Resolver`. This means that whenever we hold a `CmRef::Normal` or `cell::RefMut` and
// flip the switch on `assert_speculative` we also drop these borrows.
/// A wrapper around `RefCell` semantics that only allows writes (mutable borrows) based on a condition in the resolver.
#[derive(Default)]
pub(crate) struct CmRefCell<T> {
borrow: Cell<isize>,
value: UnsafeCell<T>,
inner: RefCell<T>,
}

@LorrensP-2158466 LorrensP-2158466 Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I am really inclined to just switch between isize and AtomicIsize. That way we can never go wrong with aliased borrows

View changes since the review

@petrochenkov

Copy link
Copy Markdown
Contributor

Benchmarking the changes in #160064.

Comment thread compiler/rustc_resolve/src/lib.rs Outdated
//
// Thus, these `impl`s rely entirely on safe usage of `RefOrMut::new`.
unsafe impl<'a, T: DynSync> DynSync for RefOrMut<'a, T> {}
unsafe impl<'a, T: DynSync> DynSend for RefOrMut<'a, T> {}

@petrochenkov petrochenkov Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This DynSend impl is not used anywhere and can be removed.

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DynSync impl here is also unnecessary, to avoid it we only need a second RefOrMut constructor taking an immutable reference petrochenkov@239c542.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, nice catch. This would remove the unsafe on RefOrMut::new as well :D.

@LorrensP-2158466

LorrensP-2158466 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

I'm also tempted to add extra methods for CmCell and CmRefCell that accept a &mut Resolver as a "token" that we can do mutations without checking assert_speculative.

@LorrensP-2158466

Copy link
Copy Markdown
Contributor Author

https://github.com/LorrensP-2158466/ref_mut/tree/main has the code for the miri tests, as you will see (and the comments in this pr explain) CmRefCell is not entirely safe.

@LorrensP-2158466

Copy link
Copy Markdown
Contributor Author

decided to create a CmToken instead of using &mut Resolver in these things, seems cleaner to me at least. @RutBot ready.

@rust-log-analyzer

This comment has been minimized.

@petrochenkov

Copy link
Copy Markdown
Contributor

#160064 already showed regressions, so let's benchmark and land this piece by piece, starting from ResolutionTable.

Also blocked on #160090.

@petrochenkov

Copy link
Copy Markdown
Contributor

the assert_speculative flag (which needs to be atomic, most likely).

At least right now it probably doesn't need to be atomic though.
assert_speculative = true, par_for_each_slice start, par_for_each_slice end, and assert_speculative = false all happens on the same thread, so there's happens-before relationship between them.
And par_for_each_slice's start and end are supposed to synchronize with everything that happens between them on all the used threads, as I understand.

@petrochenkov

Copy link
Copy Markdown
Contributor

decided to create a CmToken instead of using &mut Resolver in these things, seems cleaner to me at least

Again, we'll need to benchmark whether eliding this boolean assert even matters, considering that it's not even atomic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf-regression Performance regression. S-blocked Status: Blocked on something else such as an RFC or other implementation work. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants