Skip to content

Commit c737c62

Browse files
committed
Make Sharded an enum and specialize it for the single thread case
1 parent c1699a7 commit c737c62

File tree

1 file changed

+30
-36
lines changed

1 file changed

+30
-36
lines changed

compiler/rustc_data_structures/src/sharded.rs

+30-36
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,25 @@
11
use crate::fx::{FxHashMap, FxHasher};
22
#[cfg(parallel_compiler)]
3-
use crate::sync::is_dyn_thread_safe;
4-
use crate::sync::{CacheAligned, Lock, LockGuard};
3+
use crate::sync::{is_dyn_thread_safe, CacheAligned};
4+
use crate::sync::{Lock, LockGuard};
55
use std::borrow::Borrow;
66
use std::collections::hash_map::RawEntryMut;
77
use std::hash::{Hash, Hasher};
88
use std::mem;
99

10-
#[cfg(parallel_compiler)]
1110
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
1211
// but this should be tested on higher core count CPUs. How the `Sharded` type gets used
1312
// may also affect the ideal number of shards.
14-
const SHARD_BITS: usize = 5;
15-
16-
#[cfg(not(parallel_compiler))]
17-
const SHARD_BITS: usize = 0;
13+
const SHARD_BITS: usize = if cfg!(parallel_compiler) { 5 } else { 0 };
1814

1915
pub const SHARDS: usize = 1 << SHARD_BITS;
2016

2117
/// An array of cache-line aligned inner locked structures with convenience methods.
22-
pub struct Sharded<T> {
23-
/// This mask is used to ensure that accesses are inbounds of `shards`.
24-
/// When dynamic thread safety is off, this field is set to 0 causing only
25-
/// a single shard to be used for greater cache efficiency.
18+
/// A single field is used when the compiler uses only one thread.
19+
pub enum Sharded<T> {
20+
Single(Lock<T>),
2621
#[cfg(parallel_compiler)]
27-
mask: usize,
28-
shards: [CacheAligned<Lock<T>>; SHARDS],
22+
Shards(Box<[CacheAligned<Lock<T>>; SHARDS]>),
2923
}
3024

3125
impl<T: Default> Default for Sharded<T> {
@@ -38,29 +32,14 @@ impl<T: Default> Default for Sharded<T> {
3832
impl<T> Sharded<T> {
3933
#[inline]
4034
pub fn new(mut value: impl FnMut() -> T) -> Self {
41-
Sharded {
42-
#[cfg(parallel_compiler)]
43-
mask: if is_dyn_thread_safe() { SHARDS - 1 } else { 0 },
44-
shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
45-
}
46-
}
47-
48-
#[inline(always)]
49-
fn mask(&self) -> usize {
5035
#[cfg(parallel_compiler)]
51-
{
52-
if SHARDS == 1 { 0 } else { self.mask }
53-
}
54-
#[cfg(not(parallel_compiler))]
55-
{
56-
0
36+
if is_dyn_thread_safe() {
37+
return Sharded::Shards(Box::new(
38+
[(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
39+
));
5740
}
58-
}
5941

60-
#[inline(always)]
61-
fn count(&self) -> usize {
62-
// `self.mask` is always one below the used shard count
63-
self.mask() + 1
42+
Sharded::Single(Lock::new(value()))
6443
}
6544

6645
/// The shard is selected by hashing `val` with `FxHasher`.
@@ -75,9 +54,24 @@ impl<T> Sharded<T> {
7554
}
7655

7756
#[inline]
78-
pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> {
79-
// SAFETY: The index get ANDed with the mask, ensuring it is always inbounds.
80-
unsafe { &self.shards.get_unchecked(i & self.mask()).0 }
57+
pub fn get_shard_by_index(&self, _i: usize) -> &Lock<T> {
58+
match self {
59+
Self::Single(single) => &single,
60+
#[cfg(parallel_compiler)]
61+
Self::Shards(shards) => {
62+
// SAFETY: The index gets ANDed with the shard mask, ensuring it is always inbounds.
63+
unsafe { &shards.get_unchecked(_i & (SHARDS - 1)).0 }
64+
}
65+
}
66+
}
67+
68+
#[inline]
69+
fn count(&self) -> usize {
70+
match self {
71+
Self::Single(..) => 1,
72+
#[cfg(parallel_compiler)]
73+
Self::Shards(..) => SHARDS,
74+
}
8175
}
8276

8377
pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {

0 commit comments

Comments
 (0)