Resolver: Parallelize the import resolution loop - #158845
Resolver: Parallelize the import resolution loop#158845LorrensP-2158466 wants to merge 9 commits into
Conversation
|
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. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
17bd1cb to
9aa1069
Compare
This comment has been minimized.
This comment has been minimized.
9aa1069 to
a45ba86
Compare
|
@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.
…r=<try> Resolver: Parallelize the import resolution loop
This comment has been minimized.
This comment has been minimized.
Yes, but it doesn't mean the data in |
|
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 I have a feeling this could work, is this something that you were thinking of as well? Though unsafe is required here. |
|
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. |
67b5d60 to
c63be60
Compare
…n. When in speculative resolution, only shared borrows are allowed. An actual conditional `RefCell`.
c63be60 to
c25cae6
Compare
Same as #158845 (comment), I cannot answer without repeating the work and trying to implement in myself, but the high-level design seems plausible. |
|
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 |
…safety) comments for `ref_mut` structures
|
Updated the comments and used |
| // 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>, | ||
| } |
There was a problem hiding this comment.
Though I am really inclined to just switch between isize and AtomicIsize. That way we can never go wrong with aliased borrows
|
Benchmarking the changes in #160064. |
| // | ||
| // 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> {} |
There was a problem hiding this comment.
This DynSend impl is not used anywhere and can be removed.
There was a problem hiding this comment.
The DynSync impl here is also unnecessary, to avoid it we only need a second RefOrMut constructor taking an immutable reference petrochenkov@239c542.
There was a problem hiding this comment.
Ooh, nice catch. This would remove the unsafe on RefOrMut::new as well :D.
|
I'm also tempted to add extra methods for |
|
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) |
|
decided to create a |
This comment has been minimized.
This comment has been minimized.
At least right now it probably doesn't need to be atomic though. |
Again, we'll need to benchmark whether eliding this boolean assert even matters, considering that it's not even atomic. |
View all comments
Follow up of #159440. This pr implements the parallel part of
par_for_each_slice. And implementsDynSendandDynSyncforRefOrMutandCmCellto make the call topar_for_each_slicecompile.This is the bare minimum to make the parallel loop work and is not at all optimized, this will follow :).
r? @petrochenkov