Skip to content

Commit f08cea4

Browse files
committed
specialize the query caches
1 parent 424c216 commit f08cea4

File tree

10 files changed

+396
-200
lines changed

10 files changed

+396
-200
lines changed

compiler/rustc_data_structures/src/sharded.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::fx::{FxHashMap, FxHasher};
2-
use crate::sync::{CacheAligned, Lock, LockGuard};
2+
use crate::sync::{Lock, LockGuard};
33
use std::borrow::Borrow;
44
use std::collections::hash_map::RawEntryMut;
55
use std::hash::{Hash, Hasher};

compiler/rustc_data_structures/src/sync.rs

+104-16
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
//! [^2] `MTLockRef` is a typedef.
4141
4242
pub use crate::marker::*;
43-
use std::cell::{Cell, UnsafeCell};
43+
use std::cell::{Cell, RefCell, RefMut, UnsafeCell};
4444
use std::collections::HashMap;
4545
use std::fmt::{Debug, Formatter};
4646
use std::hash::{BuildHasher, Hash};
@@ -50,10 +50,10 @@ use std::ops::{Deref, DerefMut};
5050
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
5151

5252
mod worker_local;
53-
pub use worker_local::{Registry, WorkerLocal};
5453

5554
pub use std::sync::atomic::Ordering;
5655
pub use std::sync::atomic::Ordering::SeqCst;
56+
use std::sync::{Mutex, MutexGuard};
5757

5858
pub use vec::{AppendOnlyIndexVec, AppendOnlyVec};
5959

@@ -559,8 +559,8 @@ impl<T> FromDyn<T> {
559559
}
560560
}
561561

562-
#[derive(Default)]
563-
#[cfg_attr(parallel_compiler, repr(align(64)))]
562+
#[derive(Default, Debug)]
563+
#[repr(align(64))]
564564
pub struct CacheAligned<T>(pub T);
565565

566566
pub trait HashMapExt<K, V> {
@@ -768,6 +768,103 @@ impl<'a, T> Drop for LockGuard<'a, T> {
768768
}
769769
}
770770

771+
pub trait SLock: Copy {
772+
type Lock<T>: LockLike<T>;
773+
}
774+
775+
pub trait LockLike<T> {
776+
type LockGuard<'a>: DerefMut<Target = T>
777+
where
778+
Self: 'a;
779+
780+
fn new(val: T) -> Self;
781+
782+
fn into_inner(self) -> T;
783+
784+
fn get_mut(&mut self) -> &mut T;
785+
786+
fn try_lock(&self) -> Option<Self::LockGuard<'_>>;
787+
788+
fn lock(&self) -> Self::LockGuard<'_>;
789+
}
790+
791+
#[derive(Copy, Clone, Default)]
792+
pub struct SRefCell;
793+
794+
impl SLock for SRefCell {
795+
type Lock<T> = RefCell<T>;
796+
}
797+
798+
impl<T> LockLike<T> for RefCell<T> {
799+
type LockGuard<'a> = RefMut<'a, T> where T: 'a;
800+
801+
#[inline]
802+
fn new(val: T) -> Self {
803+
RefCell::new(val)
804+
}
805+
806+
#[inline]
807+
fn into_inner(self) -> T {
808+
self.into_inner()
809+
}
810+
811+
#[inline]
812+
fn get_mut(&mut self) -> &mut T {
813+
self.get_mut()
814+
}
815+
816+
#[inline]
817+
fn try_lock(&self) -> Option<RefMut<'_, T>> {
818+
self.try_borrow_mut().ok()
819+
}
820+
821+
#[inline(always)]
822+
#[track_caller]
823+
fn lock(&self) -> RefMut<'_, T> {
824+
self.borrow_mut()
825+
}
826+
}
827+
828+
#[derive(Copy, Clone, Default)]
829+
pub struct SMutex;
830+
831+
impl SLock for SMutex {
832+
type Lock<T> = Mutex<T>;
833+
}
834+
835+
impl<T> LockLike<T> for Mutex<T> {
836+
type LockGuard<'a> = MutexGuard<'a, T> where T: 'a;
837+
838+
#[inline]
839+
fn new(val: T) -> Self {
840+
Mutex::new(val)
841+
}
842+
843+
#[inline]
844+
fn into_inner(self) -> T {
845+
self.into_inner().unwrap()
846+
}
847+
848+
#[inline]
849+
fn get_mut(&mut self) -> &mut T {
850+
self.get_mut().unwrap()
851+
}
852+
853+
#[inline]
854+
fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
855+
self.try_lock().ok()
856+
}
857+
858+
#[inline(always)]
859+
#[track_caller]
860+
fn lock(&self) -> MutexGuard<'_, T> {
861+
self.lock().unwrap_or_else(|e| {
862+
self.clear_poison();
863+
e.into_inner()
864+
})
865+
}
866+
}
867+
771868
pub struct MappedReadGuard<'a, T: ?Sized> {
772869
raw: &'a RwLockRaw,
773870
data: *const T,
@@ -1138,7 +1235,7 @@ impl<T: Clone> Clone for RwLock<T> {
11381235
pub struct WorkerLocal<T> {
11391236
single_thread: bool,
11401237
inner: Option<T>,
1141-
mt_inner: Option<rayon_core::WorkerLocal<T>>,
1238+
mt_inner: Option<worker_local::WorkerLocal<T>>,
11421239
}
11431240

11441241
impl<T> WorkerLocal<T> {
@@ -1152,20 +1249,10 @@ impl<T> WorkerLocal<T> {
11521249
WorkerLocal {
11531250
single_thread: false,
11541251
inner: None,
1155-
mt_inner: Some(rayon_core::WorkerLocal::new(f)),
1252+
mt_inner: Some(worker_local::WorkerLocal::new(f)),
11561253
}
11571254
}
11581255
}
1159-
1160-
/// Returns the worker-local value for each thread
1161-
#[inline]
1162-
pub fn into_inner(self) -> Vec<T> {
1163-
if self.single_thread {
1164-
vec![self.inner.unwrap()]
1165-
} else {
1166-
self.mt_inner.unwrap().into_inner()
1167-
}
1168-
}
11691256
}
11701257

11711258
impl<T> Deref for WorkerLocal<T> {
@@ -1185,6 +1272,7 @@ impl<T> Deref for WorkerLocal<T> {
11851272
unsafe impl<T: Send> std::marker::Sync for WorkerLocal<T> {}
11861273

11871274
use std::thread;
1275+
pub use worker_local::Registry;
11881276

11891277
/// A type which only allows its inner value to be used in one thread.
11901278
/// It will panic if it is used on multiple threads.

compiler/rustc_data_structures/src/sync/worker_local.rs

+8-47
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::ops::Deref;
55
use std::ptr;
66
use std::sync::Arc;
77

8-
#[cfg(parallel_compiler)]
98
use {crate::cold_path, crate::sync::CacheAligned};
109

1110
/// A pointer to the `RegistryData` which uniquely identifies a registry.
@@ -21,7 +20,6 @@ impl RegistryId {
2120
///
2221
/// Note that there's a race possible where the identifer in `THREAD_DATA` could be reused
2322
/// so this can succeed from a different registry.
24-
#[cfg(parallel_compiler)]
2523
fn verify(self) -> usize {
2624
let (id, index) = THREAD_DATA.with(|data| (data.registry_id.get(), data.index.get()));
2725

@@ -33,13 +31,14 @@ impl RegistryId {
3331
}
3432
}
3533

34+
#[derive(Debug)]
3635
struct RegistryData {
3736
thread_limit: usize,
3837
threads: Lock<usize>,
3938
}
4039

4140
/// Represents a list of threads which can access worker locals.
42-
#[derive(Clone)]
41+
#[derive(Clone, Debug)]
4342
pub struct Registry(Arc<RegistryData>);
4443

4544
thread_local! {
@@ -105,73 +104,35 @@ impl Registry {
105104
/// Holds worker local values for each possible thread in a registry. You can only access the
106105
/// worker local value through the `Deref` impl on the registry associated with the thread it was
107106
/// created on. It will panic otherwise.
108-
pub struct WorkerLocal<T> {
109-
#[cfg(not(parallel_compiler))]
110-
local: T,
111-
#[cfg(parallel_compiler)]
107+
#[derive(Debug)]
108+
pub(crate) struct WorkerLocal<T> {
112109
locals: Box<[CacheAligned<T>]>,
113-
#[cfg(parallel_compiler)]
114110
registry: Registry,
115111
}
116112

117113
// This is safe because the `deref` call will return a reference to a `T` unique to each thread
118114
// or it will panic for threads without an associated local. So there isn't a need for `T` to do
119115
// it's own synchronization. The `verify` method on `RegistryId` has an issue where the the id
120116
// can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse.
121-
#[cfg(parallel_compiler)]
122117
unsafe impl<T: Send> Sync for WorkerLocal<T> {}
123118

124119
impl<T> WorkerLocal<T> {
125120
/// Creates a new worker local where the `initial` closure computes the
126121
/// value this worker local should take for each thread in the registry.
127122
#[inline]
128123
pub fn new<F: FnMut(usize) -> T>(mut initial: F) -> WorkerLocal<T> {
129-
#[cfg(parallel_compiler)]
130-
{
131-
let registry = Registry::current();
132-
WorkerLocal {
133-
locals: (0..registry.0.thread_limit).map(|i| CacheAligned(initial(i))).collect(),
134-
registry,
135-
}
136-
}
137-
#[cfg(not(parallel_compiler))]
138-
{
139-
WorkerLocal { local: initial(0) }
140-
}
141-
}
142-
143-
/// Returns the worker-local values for each thread
144-
#[inline]
145-
pub fn into_inner(self) -> impl Iterator<Item = T> {
146-
#[cfg(parallel_compiler)]
147-
{
148-
self.locals.into_vec().into_iter().map(|local| local.0)
149-
}
150-
#[cfg(not(parallel_compiler))]
151-
{
152-
std::iter::once(self.local)
124+
let registry = Registry::current();
125+
WorkerLocal {
126+
locals: (0..registry.0.thread_limit).map(|i| CacheAligned(initial(i))).collect(),
127+
registry,
153128
}
154129
}
155130
}
156131

157-
impl<T> WorkerLocal<Vec<T>> {
158-
/// Joins the elements of all the worker locals into one Vec
159-
pub fn join(self) -> Vec<T> {
160-
self.into_inner().into_iter().flat_map(|v| v).collect()
161-
}
162-
}
163-
164132
impl<T> Deref for WorkerLocal<T> {
165133
type Target = T;
166134

167135
#[inline(always)]
168-
#[cfg(not(parallel_compiler))]
169-
fn deref(&self) -> &T {
170-
&self.local
171-
}
172-
173-
#[inline(always)]
174-
#[cfg(parallel_compiler)]
175136
fn deref(&self) -> &T {
176137
// This is safe because `verify` will only return values less than
177138
// `self.registry.thread_limit` which is the size of the `self.locals` array.

0 commit comments

Comments
 (0)