Skip to content

Commit d71a46a

Browse files
committed
Auto merge of #136772 - safinaskar:parallel-2025-02-08-11-55, r=<try>
[perf run] parallel: rustc_data_structures: sync: implement RwLock as enum { Sync(parking_lot::RwLock), NoSync(RefCell) } Please, somebody, run perf. parallel: rustc_data_structures: sync: implement `RwLock` as `enum { Sync(parking_lot::RwLock), NoSync(RefCell) }` Hopefully this will make single threaded front end faster. I carefully split changes into commits. Commit messages are self-explanatory. Squashing is not recommended. cc "Parallel Rustc Front-end" #113349 r? SparrowLii `@rustbot` label: +WG-compiler-parallel
2 parents 1ff2135 + 95ce6d0 commit d71a46a

File tree

3 files changed

+279
-94
lines changed

3 files changed

+279
-94
lines changed

compiler/rustc_data_structures/src/sync.rs

+5-93
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,7 @@ pub use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize};
111111
pub use std::sync::{OnceLock, Weak};
112112

113113
pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
114-
pub use parking_lot::{
115-
MappedMutexGuard as MappedLockGuard, MappedRwLockReadGuard as MappedReadGuard,
116-
MappedRwLockWriteGuard as MappedWriteGuard, RwLockReadGuard as ReadGuard,
117-
RwLockWriteGuard as WriteGuard,
118-
};
114+
pub use parking_lot::MappedMutexGuard as MappedLockGuard;
119115
#[cfg(not(target_has_atomic = "64"))]
120116
pub use portable_atomic::AtomicU64;
121117

@@ -151,12 +147,6 @@ impl<T> MTLock<T> {
151147
}
152148
}
153149

154-
use parking_lot::RwLock as InnerRwLock;
155-
156-
/// This makes locks panic if they are already held.
157-
/// It is only useful when you are running in a single thread
158-
const ERROR_CHECKING: bool = false;
159-
160150
pub type MTLockRef<'a, T> = LRef<'a, MTLock<T>>;
161151

162152
#[derive(Default)]
@@ -175,85 +165,7 @@ impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S>
175165
}
176166
}
177167

178-
#[derive(Debug, Default)]
179-
pub struct RwLock<T>(InnerRwLock<T>);
180-
181-
impl<T> RwLock<T> {
182-
#[inline(always)]
183-
pub fn new(inner: T) -> Self {
184-
RwLock(InnerRwLock::new(inner))
185-
}
186-
187-
#[inline(always)]
188-
pub fn into_inner(self) -> T {
189-
self.0.into_inner()
190-
}
191-
192-
#[inline(always)]
193-
pub fn get_mut(&mut self) -> &mut T {
194-
self.0.get_mut()
195-
}
196-
197-
#[inline(always)]
198-
pub fn read(&self) -> ReadGuard<'_, T> {
199-
if ERROR_CHECKING {
200-
self.0.try_read().expect("lock was already held")
201-
} else {
202-
self.0.read()
203-
}
204-
}
205-
206-
#[inline(always)]
207-
#[track_caller]
208-
pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
209-
f(&*self.read())
210-
}
211-
212-
#[inline(always)]
213-
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
214-
self.0.try_write().ok_or(())
215-
}
216-
217-
#[inline(always)]
218-
pub fn write(&self) -> WriteGuard<'_, T> {
219-
if ERROR_CHECKING {
220-
self.0.try_write().expect("lock was already held")
221-
} else {
222-
self.0.write()
223-
}
224-
}
225-
226-
#[inline(always)]
227-
#[track_caller]
228-
pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
229-
f(&mut *self.write())
230-
}
231-
232-
#[inline(always)]
233-
#[track_caller]
234-
pub fn borrow(&self) -> ReadGuard<'_, T> {
235-
self.read()
236-
}
237-
238-
#[inline(always)]
239-
#[track_caller]
240-
pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
241-
self.write()
242-
}
243-
244-
#[inline(always)]
245-
pub fn leak(&self) -> &T {
246-
let guard = self.read();
247-
let ret = unsafe { &*(&raw const *guard) };
248-
std::mem::forget(guard);
249-
ret
250-
}
251-
}
252-
253-
// FIXME: Probably a bad idea
254-
impl<T: Clone> Clone for RwLock<T> {
255-
#[inline]
256-
fn clone(&self) -> Self {
257-
RwLock::new(self.borrow().clone())
258-
}
259-
}
168+
mod rwlock;
169+
pub use rwlock::{
170+
MappedReadGuard, MappedWriteGuard, ReadError, ReadGuard, RwLock, WriteError, WriteGuard,
171+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
use std::cell::{Ref, RefCell, RefMut};
2+
use std::intrinsics::unlikely;
3+
use std::ops::{Deref, DerefMut};
4+
5+
use crate::sync::mode::might_be_dyn_thread_safe;
6+
7+
#[derive(Debug)]
8+
pub enum RwLock<T> {
9+
Sync(parking_lot::RwLock<T>),
10+
NoSync(RefCell<T>),
11+
}
12+
13+
#[clippy::has_significant_drop]
14+
#[must_use = "if unused the RwLock will immediately unlock"]
15+
#[derive(Debug)]
16+
pub enum ReadGuard<'a, T> {
17+
Sync(parking_lot::RwLockReadGuard<'a, T>),
18+
NoSync(Ref<'a, T>),
19+
}
20+
21+
#[clippy::has_significant_drop]
22+
#[must_use = "if unused the RwLock will immediately unlock"]
23+
#[derive(Debug)]
24+
pub enum WriteGuard<'a, T> {
25+
Sync(parking_lot::RwLockWriteGuard<'a, T>),
26+
NoSync(RefMut<'a, T>),
27+
}
28+
29+
#[clippy::has_significant_drop]
30+
#[must_use = "if unused the RwLock will immediately unlock"]
31+
#[derive(Debug)]
32+
pub enum MappedReadGuard<'a, T> {
33+
Sync(parking_lot::MappedRwLockReadGuard<'a, T>),
34+
NoSync(Ref<'a, T>),
35+
}
36+
37+
#[clippy::has_significant_drop]
38+
#[must_use = "if unused the RwLock will immediately unlock"]
39+
#[derive(Debug)]
40+
pub enum MappedWriteGuard<'a, T> {
41+
Sync(parking_lot::MappedRwLockWriteGuard<'a, T>),
42+
NoSync(RefMut<'a, T>),
43+
}
44+
45+
#[derive(Debug)]
46+
pub struct ReadError;
47+
48+
#[derive(Debug)]
49+
pub struct WriteError;
50+
51+
impl<T> RwLock<T> {
52+
#[inline(always)]
53+
pub fn new(inner: T) -> Self {
54+
if unlikely(might_be_dyn_thread_safe()) {
55+
RwLock::Sync(parking_lot::RwLock::new(inner))
56+
} else {
57+
RwLock::NoSync(RefCell::new(inner))
58+
}
59+
}
60+
61+
#[inline(always)]
62+
pub fn into_inner(self) -> T {
63+
match self {
64+
RwLock::Sync(inner) => parking_lot::RwLock::into_inner(inner),
65+
RwLock::NoSync(inner) => RefCell::into_inner(inner),
66+
}
67+
}
68+
69+
#[inline(always)]
70+
pub fn get_mut(&mut self) -> &mut T {
71+
match self {
72+
RwLock::Sync(inner) => parking_lot::RwLock::get_mut(inner),
73+
RwLock::NoSync(inner) => RefCell::get_mut(inner),
74+
}
75+
}
76+
77+
#[inline(always)]
78+
#[track_caller]
79+
pub fn read(&self) -> ReadGuard<'_, T> {
80+
match self {
81+
RwLock::Sync(inner) => ReadGuard::Sync(inner.read()),
82+
RwLock::NoSync(inner) => ReadGuard::NoSync(inner.borrow()),
83+
}
84+
}
85+
86+
#[inline(always)]
87+
pub fn try_read(&self) -> Result<ReadGuard<'_, T>, ReadError> {
88+
match self {
89+
RwLock::Sync(inner) => Ok(ReadGuard::Sync(inner.try_read().ok_or(ReadError)?)),
90+
RwLock::NoSync(inner) => {
91+
Ok(ReadGuard::NoSync(inner.try_borrow().map_err(|_| ReadError)?))
92+
}
93+
}
94+
}
95+
96+
#[inline(always)]
97+
#[track_caller]
98+
pub fn write(&self) -> WriteGuard<'_, T> {
99+
match self {
100+
RwLock::Sync(inner) => WriteGuard::Sync(inner.write()),
101+
RwLock::NoSync(inner) => WriteGuard::NoSync(inner.borrow_mut()),
102+
}
103+
}
104+
105+
#[inline(always)]
106+
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, WriteError> {
107+
match self {
108+
RwLock::Sync(inner) => Ok(WriteGuard::Sync(inner.try_write().ok_or(WriteError)?)),
109+
RwLock::NoSync(inner) => {
110+
Ok(WriteGuard::NoSync(inner.try_borrow_mut().map_err(|_| WriteError)?))
111+
}
112+
}
113+
}
114+
115+
#[inline(always)]
116+
#[track_caller]
117+
pub fn borrow(&self) -> ReadGuard<'_, T> {
118+
self.read()
119+
}
120+
121+
#[inline(always)]
122+
pub fn try_borrow(&self) -> Result<ReadGuard<'_, T>, ReadError> {
123+
self.try_read()
124+
}
125+
126+
#[inline(always)]
127+
#[track_caller]
128+
pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
129+
self.write()
130+
}
131+
132+
#[inline(always)]
133+
pub fn try_borrow_mut(&self) -> Result<WriteGuard<'_, T>, WriteError> {
134+
self.try_write()
135+
}
136+
}
137+
138+
impl<T: Default> Default for RwLock<T> {
139+
#[inline(always)]
140+
fn default() -> Self {
141+
RwLock::<T>::new(Default::default())
142+
}
143+
}
144+
145+
impl<'a, T> ReadGuard<'a, T> {
146+
#[inline(always)]
147+
pub fn map<U, F>(s: Self, f: F) -> MappedReadGuard<'a, U>
148+
where
149+
F: FnOnce(&T) -> &U,
150+
{
151+
match s {
152+
ReadGuard::Sync(guard) => {
153+
MappedReadGuard::Sync(parking_lot::RwLockReadGuard::map(guard, f))
154+
}
155+
ReadGuard::NoSync(guard) => MappedReadGuard::NoSync(Ref::map(guard, f)),
156+
}
157+
}
158+
}
159+
160+
impl<'a, T> WriteGuard<'a, T> {
161+
#[inline(always)]
162+
pub fn map<U, F>(s: Self, f: F) -> MappedWriteGuard<'a, U>
163+
where
164+
F: FnOnce(&mut T) -> &mut U,
165+
{
166+
match s {
167+
WriteGuard::Sync(guard) => {
168+
MappedWriteGuard::Sync(parking_lot::RwLockWriteGuard::map(guard, f))
169+
}
170+
WriteGuard::NoSync(guard) => MappedWriteGuard::NoSync(RefMut::map(guard, f)),
171+
}
172+
}
173+
}
174+
175+
impl<'a, T> Deref for ReadGuard<'a, T> {
176+
type Target = T;
177+
178+
#[inline(always)]
179+
fn deref(&self) -> &T {
180+
match self {
181+
ReadGuard::Sync(guard) => Deref::deref(guard),
182+
ReadGuard::NoSync(guard) => Deref::deref(guard),
183+
}
184+
}
185+
}
186+
187+
impl<'a, T> Deref for WriteGuard<'a, T> {
188+
type Target = T;
189+
190+
#[inline(always)]
191+
fn deref(&self) -> &T {
192+
match self {
193+
WriteGuard::Sync(guard) => Deref::deref(guard),
194+
WriteGuard::NoSync(guard) => Deref::deref(guard),
195+
}
196+
}
197+
}
198+
199+
impl<'a, T> DerefMut for WriteGuard<'a, T> {
200+
#[inline(always)]
201+
fn deref_mut(&mut self) -> &mut T {
202+
match self {
203+
WriteGuard::Sync(guard) => DerefMut::deref_mut(guard),
204+
WriteGuard::NoSync(guard) => DerefMut::deref_mut(guard),
205+
}
206+
}
207+
}
208+
209+
impl<'a, T> MappedReadGuard<'a, T> {
210+
#[inline(always)]
211+
pub fn map<U, F>(s: Self, f: F) -> MappedReadGuard<'a, U>
212+
where
213+
F: FnOnce(&T) -> &U,
214+
{
215+
match s {
216+
MappedReadGuard::Sync(guard) => {
217+
MappedReadGuard::Sync(parking_lot::MappedRwLockReadGuard::map(guard, f))
218+
}
219+
MappedReadGuard::NoSync(guard) => MappedReadGuard::NoSync(Ref::map(guard, f)),
220+
}
221+
}
222+
}
223+
224+
impl<'a, T> MappedWriteGuard<'a, T> {
225+
#[inline(always)]
226+
pub fn map<U, F>(s: Self, f: F) -> MappedWriteGuard<'a, U>
227+
where
228+
F: FnOnce(&mut T) -> &mut U,
229+
{
230+
match s {
231+
MappedWriteGuard::Sync(guard) => {
232+
MappedWriteGuard::Sync(parking_lot::MappedRwLockWriteGuard::map(guard, f))
233+
}
234+
MappedWriteGuard::NoSync(guard) => MappedWriteGuard::NoSync(RefMut::map(guard, f)),
235+
}
236+
}
237+
}
238+
239+
impl<'a, T> Deref for MappedReadGuard<'a, T> {
240+
type Target = T;
241+
242+
#[inline(always)]
243+
fn deref(&self) -> &T {
244+
match self {
245+
MappedReadGuard::Sync(guard) => Deref::deref(guard),
246+
MappedReadGuard::NoSync(guard) => Deref::deref(guard),
247+
}
248+
}
249+
}
250+
251+
impl<'a, T> Deref for MappedWriteGuard<'a, T> {
252+
type Target = T;
253+
254+
#[inline(always)]
255+
fn deref(&self) -> &T {
256+
match self {
257+
MappedWriteGuard::Sync(guard) => Deref::deref(guard),
258+
MappedWriteGuard::NoSync(guard) => Deref::deref(guard),
259+
}
260+
}
261+
}
262+
263+
impl<'a, T> DerefMut for MappedWriteGuard<'a, T> {
264+
#[inline(always)]
265+
fn deref_mut(&mut self) -> &mut T {
266+
match self {
267+
MappedWriteGuard::Sync(guard) => DerefMut::deref_mut(guard),
268+
MappedWriteGuard::NoSync(guard) => DerefMut::deref_mut(guard),
269+
}
270+
}
271+
}

0 commit comments

Comments
 (0)