Skip to content

Commit 61efe9d

Browse files
committed
Auto merge of #111713 - Zoxc:lock-switch, r=nnethercote
Use conditional synchronization for Lock This changes `Lock` to use synchronization only if `mode::is_dyn_thread_safe` could be true. This reduces overhead for the parallel compiler running with 1 thread. The emitters are changed to use `DynSend` instead of `Send` so they can still use `Lock`. A Rayon thread pool is not used with 1 thread anymore, as session globals contains `Lock`s which are no longer `Sync`. Performance improvement with 1 thread and `cfg(parallel_compiler)`: <table><tr><td rowspan="2">Benchmark</td><td colspan="1"><b>Before</b></th><td colspan="2"><b>After</b></th></tr><tr><td align="right">Time</td><td align="right">Time</td><td align="right">%</th></tr><tr><td>🟣 <b>clap</b>:check</td><td align="right">1.7665s</td><td align="right">1.7336s</td><td align="right">💚 -1.86%</td></tr><tr><td>🟣 <b>hyper</b>:check</td><td align="right">0.2780s</td><td align="right">0.2736s</td><td align="right">💚 -1.61%</td></tr><tr><td>🟣 <b>regex</b>:check</td><td align="right">0.9994s</td><td align="right">0.9824s</td><td align="right">💚 -1.70%</td></tr><tr><td>🟣 <b>syn</b>:check</td><td align="right">1.5875s</td><td align="right">1.5656s</td><td align="right">💚 -1.38%</td></tr><tr><td>🟣 <b>syntex_syntax</b>:check</td><td align="right">6.0682s</td><td align="right">5.9532s</td><td align="right">💚 -1.90%</td></tr><tr><td>Total</td><td align="right">10.6997s</td><td align="right">10.5083s</td><td align="right">💚 -1.79%</td></tr><tr><td>Summary</td><td align="right">1.0000s</td><td align="right">0.9831s</td><td align="right">💚 -1.69%</td></tr></table> cc `@SparrowLii`
2 parents 7659abc + d35179f commit 61efe9d

File tree

13 files changed

+368
-139
lines changed

13 files changed

+368
-139
lines changed

compiler/rustc_data_structures/src/marker.rs

-2
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ cfg_if!(
9292
[std::collections::BTreeMap<K, V, A> where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend]
9393
[Vec<T, A> where T: DynSend, A: std::alloc::Allocator + DynSend]
9494
[Box<T, A> where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend]
95-
[crate::sync::Lock<T> where T: DynSend]
9695
[crate::sync::RwLock<T> where T: DynSend]
9796
[crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool]
9897
[rustc_arena::TypedArena<T> where T: DynSend]
@@ -171,7 +170,6 @@ cfg_if!(
171170
[std::collections::BTreeMap<K, V, A> where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync]
172171
[Vec<T, A> where T: DynSync, A: std::alloc::Allocator + DynSync]
173172
[Box<T, A> where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync]
174-
[crate::sync::Lock<T> where T: DynSend]
175173
[crate::sync::RwLock<T> where T: DynSend + DynSync]
176174
[crate::sync::OneThread<T> where T]
177175
[crate::sync::WorkerLocal<T> where T: DynSend]

compiler/rustc_data_structures/src/sync.rs

+19-86
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
//! | `AtomicU64` | `Cell<u64>` | `atomic::AtomicU64` |
2727
//! | `AtomicUsize` | `Cell<usize>` | `atomic::AtomicUsize` |
2828
//! | | | |
29-
//! | `Lock<T>` | `RefCell<T>` | `parking_lot::Mutex<T>` |
29+
//! | `Lock<T>` | `RefCell<T>` | `RefCell<T>` or |
30+
//! | | | `parking_lot::Mutex<T>` |
3031
//! | `RwLock<T>` | `RefCell<T>` | `parking_lot::RwLock<T>` |
3132
//! | `MTLock<T>` [^1] | `T` | `Lock<T>` |
3233
//! | `MTLockRef<'a, T>` [^2] | `&'a mut MTLock<T>` | `&'a MTLock<T>` |
@@ -45,6 +46,9 @@ use std::hash::{BuildHasher, Hash};
4546
use std::ops::{Deref, DerefMut};
4647
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
4748

49+
mod lock;
50+
pub use lock::{Lock, LockGuard};
51+
4852
mod worker_local;
4953
pub use worker_local::{Registry, WorkerLocal};
5054

@@ -75,6 +79,13 @@ mod mode {
7579
}
7680
}
7781

82+
// Whether thread safety might be enabled.
83+
#[inline]
84+
#[cfg(parallel_compiler)]
85+
pub fn might_be_dyn_thread_safe() -> bool {
86+
DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE
87+
}
88+
7889
// Only set by the `-Z threads` compile option
7990
pub fn set_dyn_thread_safe_mode(mode: bool) {
8091
let set: u8 = if mode { DYN_THREAD_SAFE } else { DYN_NOT_THREAD_SAFE };
@@ -94,14 +105,15 @@ pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
94105

95106
cfg_if! {
96107
if #[cfg(not(parallel_compiler))] {
108+
use std::ops::Add;
109+
use std::cell::Cell;
110+
97111
pub unsafe auto trait Send {}
98112
pub unsafe auto trait Sync {}
99113

100114
unsafe impl<T> Send for T {}
101115
unsafe impl<T> Sync for T {}
102116

103-
use std::ops::Add;
104-
105117
/// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
106118
/// It has explicit ordering arguments and is only intended for use with
107119
/// the native atomic types.
@@ -255,15 +267,11 @@ cfg_if! {
255267
pub use std::cell::Ref as MappedReadGuard;
256268
pub use std::cell::RefMut as WriteGuard;
257269
pub use std::cell::RefMut as MappedWriteGuard;
258-
pub use std::cell::RefMut as LockGuard;
259270
pub use std::cell::RefMut as MappedLockGuard;
260271

261272
pub use std::cell::OnceCell;
262273

263274
use std::cell::RefCell as InnerRwLock;
264-
use std::cell::RefCell as InnerLock;
265-
266-
use std::cell::Cell;
267275

268276
pub type MTLockRef<'a, T> = &'a mut MTLock<T>;
269277

@@ -305,6 +313,8 @@ cfg_if! {
305313
}
306314
}
307315
} else {
316+
use parking_lot::Mutex;
317+
308318
pub use std::marker::Send as Send;
309319
pub use std::marker::Sync as Sync;
310320

@@ -313,7 +323,6 @@ cfg_if! {
313323
pub use parking_lot::RwLockWriteGuard as WriteGuard;
314324
pub use parking_lot::MappedRwLockWriteGuard as MappedWriteGuard;
315325

316-
pub use parking_lot::MutexGuard as LockGuard;
317326
pub use parking_lot::MappedMutexGuard as MappedLockGuard;
318327

319328
pub use std::sync::OnceLock as OnceCell;
@@ -355,7 +364,6 @@ cfg_if! {
355364
}
356365
}
357366

358-
use parking_lot::Mutex as InnerLock;
359367
use parking_lot::RwLock as InnerRwLock;
360368

361369
use std::thread;
@@ -441,7 +449,7 @@ cfg_if! {
441449
) {
442450
if mode::is_dyn_thread_safe() {
443451
let for_each = FromDyn::from(for_each);
444-
let panic: Lock<Option<_>> = Lock::new(None);
452+
let panic: Mutex<Option<_>> = Mutex::new(None);
445453
t.into_par_iter().for_each(|i| if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) {
446454
let mut l = panic.lock();
447455
if l.is_none() {
@@ -479,7 +487,7 @@ cfg_if! {
479487
map: impl Fn(I) -> R + DynSync + DynSend
480488
) -> C {
481489
if mode::is_dyn_thread_safe() {
482-
let panic: Lock<Option<_>> = Lock::new(None);
490+
let panic: Mutex<Option<_>> = Mutex::new(None);
483491
let map = FromDyn::from(map);
484492
// We catch panics here ensuring that all the loop iterations execute.
485493
let r = t.into_par_iter().filter_map(|i| {
@@ -542,81 +550,6 @@ impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S>
542550
}
543551
}
544552

545-
#[derive(Debug)]
546-
pub struct Lock<T>(InnerLock<T>);
547-
548-
impl<T> Lock<T> {
549-
#[inline(always)]
550-
pub fn new(inner: T) -> Self {
551-
Lock(InnerLock::new(inner))
552-
}
553-
554-
#[inline(always)]
555-
pub fn into_inner(self) -> T {
556-
self.0.into_inner()
557-
}
558-
559-
#[inline(always)]
560-
pub fn get_mut(&mut self) -> &mut T {
561-
self.0.get_mut()
562-
}
563-
564-
#[cfg(parallel_compiler)]
565-
#[inline(always)]
566-
pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
567-
self.0.try_lock()
568-
}
569-
570-
#[cfg(not(parallel_compiler))]
571-
#[inline(always)]
572-
pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
573-
self.0.try_borrow_mut().ok()
574-
}
575-
576-
#[cfg(parallel_compiler)]
577-
#[inline(always)]
578-
#[track_caller]
579-
pub fn lock(&self) -> LockGuard<'_, T> {
580-
if ERROR_CHECKING {
581-
self.0.try_lock().expect("lock was already held")
582-
} else {
583-
self.0.lock()
584-
}
585-
}
586-
587-
#[cfg(not(parallel_compiler))]
588-
#[inline(always)]
589-
#[track_caller]
590-
pub fn lock(&self) -> LockGuard<'_, T> {
591-
self.0.borrow_mut()
592-
}
593-
594-
#[inline(always)]
595-
#[track_caller]
596-
pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
597-
f(&mut *self.lock())
598-
}
599-
600-
#[inline(always)]
601-
#[track_caller]
602-
pub fn borrow(&self) -> LockGuard<'_, T> {
603-
self.lock()
604-
}
605-
606-
#[inline(always)]
607-
#[track_caller]
608-
pub fn borrow_mut(&self) -> LockGuard<'_, T> {
609-
self.lock()
610-
}
611-
}
612-
613-
impl<T: Default> Default for Lock<T> {
614-
#[inline]
615-
fn default() -> Self {
616-
Lock::new(T::default())
617-
}
618-
}
619-
620553
#[derive(Debug, Default)]
621554
pub struct RwLock<T>(InnerRwLock<T>);
622555

0 commit comments

Comments
 (0)