1
Fork 0

Rollup merge of #136858 - safinaskar:parallel-cleanup-2025-02-11-07-54, r=SparrowLii

Parallel-compiler-related cleanup

Parallel-compiler-related cleanup

I carefully split changes into commits. Commit messages are self-explanatory. Squashing is not recommended.

cc "Parallel Rustc Front-end" https://github.com/rust-lang/rust/issues/113349

r? SparrowLii

``@rustbot`` label: +WG-compiler-parallel
This commit is contained in:
Jacob Pratt 2025-02-13 03:53:31 -05:00 committed by GitHub
commit 1f669fdc7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 17 additions and 77 deletions

View file

@ -710,10 +710,6 @@ pub struct ThinBuffer {
context: Arc<SyncContext>, context: Arc<SyncContext>,
} }
// TODO: check if this makes sense to make ThinBuffer Send and Sync.
unsafe impl Send for ThinBuffer {}
unsafe impl Sync for ThinBuffer {}
impl ThinBuffer { impl ThinBuffer {
pub(crate) fn new(context: &Arc<SyncContext>) -> Self { pub(crate) fn new(context: &Arc<SyncContext>) -> Self {
Self { context: Arc::clone(context) } Self { context: Arc::clone(context) }

View file

@ -245,9 +245,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
} }
} }
unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
unsafe impl Sync for LlvmCodegenBackend {}
impl LlvmCodegenBackend { impl LlvmCodegenBackend {
pub fn new() -> Box<dyn CodegenBackend> { pub fn new() -> Box<dyn CodegenBackend> {
Box::new(LlvmCodegenBackend(())) Box::new(LlvmCodegenBackend(()))

View file

@ -2,11 +2,6 @@ use std::borrow::Borrow;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
// Use our fake Send/Sync traits when on not parallel compiler,
// so that `OwnedSlice` only implements/requires Send/Sync
// for parallel compiler builds.
use crate::sync;
/// An owned slice. /// An owned slice.
/// ///
/// This is similar to `Arc<[u8]>` but allows slicing and using anything as the /// This is similar to `Arc<[u8]>` but allows slicing and using anything as the
@ -34,7 +29,7 @@ pub struct OwnedSlice {
// \/ // \/
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770) // ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
#[expect(dead_code)] #[expect(dead_code)]
owner: Arc<dyn sync::Send + sync::Sync>, owner: Arc<dyn Send + Sync>,
} }
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function. /// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
@ -61,7 +56,7 @@ pub struct OwnedSlice {
/// ``` /// ```
pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
where where
O: sync::Send + sync::Sync + 'static, O: Send + Sync + 'static,
F: FnOnce(&O) -> &[u8], F: FnOnce(&O) -> &[u8],
{ {
try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok() try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
@ -72,7 +67,7 @@ where
/// See [`slice_owned`] for the infallible version. /// See [`slice_owned`] for the infallible version.
pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E> pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
where where
O: sync::Send + sync::Sync + 'static, O: Send + Sync + 'static,
F: FnOnce(&O) -> Result<&[u8], E>, F: FnOnce(&O) -> Result<&[u8], E>,
{ {
// We wrap the owner of the bytes in, so it doesn't move. // We wrap the owner of the bytes in, so it doesn't move.
@ -139,10 +134,10 @@ impl Borrow<[u8]> for OwnedSlice {
} }
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send` // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
unsafe impl sync::Send for OwnedSlice {} unsafe impl Send for OwnedSlice {}
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync` // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
unsafe impl sync::Sync for OwnedSlice {} unsafe impl Sync for OwnedSlice {}
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

View file

@ -18,14 +18,8 @@
//! //!
//! | Type | Serial version | Parallel version | //! | Type | Serial version | Parallel version |
//! | ----------------------- | ------------------- | ------------------------------- | //! | ----------------------- | ------------------- | ------------------------------- |
//! |` Weak<T>` | `rc::Weak<T>` | `sync::Weak<T>` |
//! | `LRef<'a, T>` [^2] | `&'a mut T` | `&'a T` | //! | `LRef<'a, T>` [^2] | `&'a mut T` | `&'a T` |
//! | | | | //! | | | |
//! | `AtomicBool` | `Cell<bool>` | `atomic::AtomicBool` |
//! | `AtomicU32` | `Cell<u32>` | `atomic::AtomicU32` |
//! | `AtomicU64` | `Cell<u64>` | `atomic::AtomicU64` |
//! | `AtomicUsize` | `Cell<usize>` | `atomic::AtomicUsize` |
//! | | | |
//! | `Lock<T>` | `RefCell<T>` | `RefCell<T>` or | //! | `Lock<T>` | `RefCell<T>` | `RefCell<T>` or |
//! | | | `parking_lot::Mutex<T>` | //! | | | `parking_lot::Mutex<T>` |
//! | `RwLock<T>` | `RefCell<T>` | `parking_lot::RwLock<T>` | //! | `RwLock<T>` | `RefCell<T>` | `parking_lot::RwLock<T>` |
@ -103,18 +97,15 @@ mod mode {
// FIXME(parallel_compiler): Get rid of these aliases across the compiler. // FIXME(parallel_compiler): Get rid of these aliases across the compiler.
pub use std::marker::{Send, Sync}; pub use std::sync::OnceLock;
// Use portable AtomicU64 for targets without native 64-bit atomics // Use portable AtomicU64 for targets without native 64-bit atomics
#[cfg(target_has_atomic = "64")] #[cfg(target_has_atomic = "64")]
pub use std::sync::atomic::AtomicU64; pub use std::sync::atomic::AtomicU64;
pub use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize};
pub use std::sync::{OnceLock, Weak};
pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
pub use parking_lot::{ pub use parking_lot::{
MappedMutexGuard as MappedLockGuard, MappedRwLockReadGuard as MappedReadGuard, MappedRwLockReadGuard as MappedReadGuard, MappedRwLockWriteGuard as MappedWriteGuard,
MappedRwLockWriteGuard as MappedWriteGuard, RwLockReadGuard as ReadGuard, RwLockReadGuard as ReadGuard, RwLockWriteGuard as WriteGuard,
RwLockWriteGuard as WriteGuard,
}; };
#[cfg(not(target_has_atomic = "64"))] #[cfg(not(target_has_atomic = "64"))]
pub use portable_atomic::AtomicU64; pub use portable_atomic::AtomicU64;
@ -203,12 +194,6 @@ impl<T> RwLock<T> {
} }
} }
#[inline(always)]
#[track_caller]
pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
f(&*self.read())
}
#[inline(always)] #[inline(always)]
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> { pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
self.0.try_write().ok_or(()) self.0.try_write().ok_or(())
@ -223,12 +208,6 @@ impl<T> RwLock<T> {
} }
} }
#[inline(always)]
#[track_caller]
pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
f(&mut *self.write())
}
#[inline(always)] #[inline(always)]
#[track_caller] #[track_caller]
pub fn borrow(&self) -> ReadGuard<'_, T> { pub fn borrow(&self) -> ReadGuard<'_, T> {
@ -240,20 +219,4 @@ impl<T> RwLock<T> {
pub fn borrow_mut(&self) -> WriteGuard<'_, T> { pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
self.write() self.write()
} }
#[inline(always)]
pub fn leak(&self) -> &T {
let guard = self.read();
let ret = unsafe { &*(&raw const *guard) };
std::mem::forget(guard);
ret
}
}
// FIXME: Probably a bad idea
impl<T: Clone> Clone for RwLock<T> {
#[inline]
fn clone(&self) -> Self {
RwLock::new(self.borrow().clone())
}
} }

View file

@ -3,9 +3,9 @@ use std::intrinsics::likely;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::ptr::NonNull; use std::ptr::NonNull;
use std::sync::atomic::Ordering; use std::sync::atomic::{AtomicBool, Ordering};
use crate::sync::{AtomicBool, DynSend, DynSync, ReadGuard, RwLock, WriteGuard}; use crate::sync::{DynSend, DynSync, ReadGuard, RwLock, WriteGuard};
/// A type which allows mutation using a lock until /// A type which allows mutation using a lock until
/// the value is frozen and can be accessed lock-free. /// the value is frozen and can be accessed lock-free.

View file

@ -106,12 +106,6 @@ pub struct WorkerLocal<T> {
registry: Registry, registry: Registry,
} }
// This is safe because the `deref` call will return a reference to a `T` unique to each thread
// or it will panic for threads without an associated local. So there isn't a need for `T` to do
// it's own synchronization. The `verify` method on `RegistryId` has an issue where the id
// can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse.
unsafe impl<T: Send> Sync for WorkerLocal<T> {}
impl<T> WorkerLocal<T> { impl<T> WorkerLocal<T> {
/// Creates a new worker local where the `initial` closure computes the /// Creates a new worker local where the `initial` closure computes the
/// value this worker local should take for each thread in the registry. /// value this worker local should take for each thread in the registry.
@ -138,6 +132,11 @@ impl<T> Deref for WorkerLocal<T> {
fn deref(&self) -> &T { fn deref(&self) -> &T {
// This is safe because `verify` will only return values less than // This is safe because `verify` will only return values less than
// `self.registry.thread_limit` which is the size of the `self.locals` array. // `self.registry.thread_limit` which is the size of the `self.locals` array.
// The `deref` call will return a reference to a `T` unique to each thread
// or it will panic for threads without an associated local. So there isn't a need for `T` to do
// it's own synchronization. The `verify` method on `RegistryId` has an issue where the id
// can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse.
unsafe { &self.locals.get_unchecked(self.registry.id().verify()).0 } unsafe { &self.locals.get_unchecked(self.registry.id().verify()).0 }
} }
} }

View file

@ -4,14 +4,14 @@ use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::Ordering; use std::sync::atomic::{AtomicU32, Ordering};
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef}; use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef};
use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::sharded::{self, Sharded};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock}; use rustc_data_structures::sync::{AtomicU64, Lock};
use rustc_data_structures::unord::UnordMap; use rustc_data_structures::unord::UnordMap;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable}; use rustc_macros::{Decodable, Encodable};

View file

@ -595,11 +595,6 @@
# Whether to always use incremental compilation when building rustc # Whether to always use incremental compilation when building rustc
#incremental = false #incremental = false
# Build a multi-threaded rustc. This allows users to use parallel rustc
# via the unstable option `-Z threads=n`.
# This option is deprecated and always true.
#parallel-compiler = true
# The default linker that will be hard-coded into the generated # The default linker that will be hard-coded into the generated
# compiler for targets that don't specify a default linker explicitly # compiler for targets that don't specify a default linker explicitly
# in their target specifications. Note that this is not the linker # in their target specifications. Note that this is not the linker

View file

@ -46,8 +46,6 @@ are implemented differently depending on whether `parallel-compiler` is true.
| data structure | parallel | non-parallel | | data structure | parallel | non-parallel |
| -------------------------------- | --------------------------------------------------- | ------------ | | -------------------------------- | --------------------------------------------------- | ------------ |
| Weak | std::sync::Weak | std::rc::Weak |
| Atomic{Bool}/{Usize}/{U32}/{U64} | std::sync::atomic::Atomic{Bool}/{Usize}/{U32}/{U64} | (std::cell::Cell<bool/usize/u32/u64>) |
| OnceCell | std::sync::OnceLock | std::cell::OnceCell | | OnceCell | std::sync::OnceLock | std::cell::OnceCell |
| Lock\<T> | (parking_lot::Mutex\<T>) | (std::cell::RefCell) | | Lock\<T> | (parking_lot::Mutex\<T>) | (std::cell::RefCell) |
| RwLock\<T> | (parking_lot::RwLock\<T>) | (std::cell::RefCell) | | RwLock\<T> | (parking_lot::RwLock\<T>) | (std::cell::RefCell) |
@ -58,7 +56,6 @@ are implemented differently depending on whether `parallel-compiler` is true.
| WriteGuard | parking_lot::RwLockWriteGuard | std::cell::RefMut | | WriteGuard | parking_lot::RwLockWriteGuard | std::cell::RefMut |
| MappedWriteGuard | parking_lot::MappedRwLockWriteGuard | std::cell::RefMut | | MappedWriteGuard | parking_lot::MappedRwLockWriteGuard | std::cell::RefMut |
| LockGuard | parking_lot::MutexGuard | std::cell::RefMut | | LockGuard | parking_lot::MutexGuard | std::cell::RefMut |
| MappedLockGuard | parking_lot::MappedMutexGuard | std::cell::RefMut |
- These thread-safe data structures are interspersed during compilation which - These thread-safe data structures are interspersed during compilation which
can cause lock contention resulting in degraded performance as the number of can cause lock contention resulting in degraded performance as the number of
@ -173,12 +170,10 @@ Here are some resources that can be used to learn more:
- [This list of interior mutability in the compiler by nikomatsakis][imlist] - [This list of interior mutability in the compiler by nikomatsakis][imlist]
[`rayon`]: https://crates.io/crates/rayon [`rayon`]: https://crates.io/crates/rayon
[Arc]: https://doc.rust-lang.org/std/sync/struct.Arc.html
[imlist]: https://github.com/nikomatsakis/rustc-parallelization/blob/master/interior-mutability-list.md [imlist]: https://github.com/nikomatsakis/rustc-parallelization/blob/master/interior-mutability-list.md
[irlo0]: https://internals.rust-lang.org/t/parallelizing-rustc-using-rayon/6606 [irlo0]: https://internals.rust-lang.org/t/parallelizing-rustc-using-rayon/6606
[irlo1]: https://internals.rust-lang.org/t/help-test-parallel-rustc/11503 [irlo1]: https://internals.rust-lang.org/t/help-test-parallel-rustc/11503
[monomorphization]: backend/monomorph.md [monomorphization]: backend/monomorph.md
[parallel-rustdoc]: https://github.com/rust-lang/rust/issues/82741 [parallel-rustdoc]: https://github.com/rust-lang/rust/issues/82741
[Rc]: https://doc.rust-lang.org/std/rc/struct.Rc.html
[rustc-rayon]: https://github.com/rust-lang/rustc-rayon [rustc-rayon]: https://github.com/rust-lang/rustc-rayon
[tracking]: https://github.com/rust-lang/rust/issues/48685 [tracking]: https://github.com/rust-lang/rust/issues/48685