about summary refs log tree commit diff
path: root/compiler/rustc_data_structures/src/sharded.rs
diff options
context:
space:
mode:
authorJohn Kåre Alsaker <john.kare.alsaker@gmail.com>2023-08-15 16:03:17 +0200
committerJohn Kåre Alsaker <john.kare.alsaker@gmail.com>2023-08-15 17:22:48 +0200
commitc737c62e70cf8627e01e0b3a1088e96bff1b154d (patch)
treea5b13f71dad441015bc74dc87a912445a5b24f71 /compiler/rustc_data_structures/src/sharded.rs
parentc1699a79a603faa8b522a4b51553b6781913a50e (diff)
downloadrust-c737c62e70cf8627e01e0b3a1088e96bff1b154d.tar.gz
rust-c737c62e70cf8627e01e0b3a1088e96bff1b154d.zip
Make Sharded an enum and specialize it for the single thread case
Diffstat (limited to 'compiler/rustc_data_structures/src/sharded.rs')
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs66
1 files changed, 30 insertions, 36 deletions
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 40cbf14958e..6bc0b346d92 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,31 +1,25 @@
 use crate::fx::{FxHashMap, FxHasher};
 #[cfg(parallel_compiler)]
-use crate::sync::is_dyn_thread_safe;
-use crate::sync::{CacheAligned, Lock, LockGuard};
+use crate::sync::{is_dyn_thread_safe, CacheAligned};
+use crate::sync::{Lock, LockGuard};
 use std::borrow::Borrow;
 use std::collections::hash_map::RawEntryMut;
 use std::hash::{Hash, Hasher};
 use std::mem;
 
-#[cfg(parallel_compiler)]
 // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
 // but this should be tested on higher core count CPUs. How the `Sharded` type gets used
 // may also affect the ideal number of shards.
-const SHARD_BITS: usize = 5;
-
-#[cfg(not(parallel_compiler))]
-const SHARD_BITS: usize = 0;
+const SHARD_BITS: usize = if cfg!(parallel_compiler) { 5 } else { 0 };
 
 pub const SHARDS: usize = 1 << SHARD_BITS;
 
 /// An array of cache-line aligned inner locked structures with convenience methods.
-pub struct Sharded<T> {
-    /// This mask is used to ensure that accesses are inbounds of `shards`.
-    /// When dynamic thread safety is off, this field is set to 0 causing only
-    /// a single shard to be used for greater cache efficiency.
+/// A single field is used when the compiler uses only one thread.
+pub enum Sharded<T> {
+    Single(Lock<T>),
     #[cfg(parallel_compiler)]
-    mask: usize,
-    shards: [CacheAligned<Lock<T>>; SHARDS],
+    Shards(Box<[CacheAligned<Lock<T>>; SHARDS]>),
 }
 
 impl<T: Default> Default for Sharded<T> {
@@ -38,29 +32,14 @@ impl<T: Default> Default for Sharded<T> {
 impl<T> Sharded<T> {
     #[inline]
     pub fn new(mut value: impl FnMut() -> T) -> Self {
-        Sharded {
-            #[cfg(parallel_compiler)]
-            mask: if is_dyn_thread_safe() { SHARDS - 1 } else { 0 },
-            shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
-        }
-    }
-
-    #[inline(always)]
-    fn mask(&self) -> usize {
         #[cfg(parallel_compiler)]
-        {
-            if SHARDS == 1 { 0 } else { self.mask }
-        }
-        #[cfg(not(parallel_compiler))]
-        {
-            0
+        if is_dyn_thread_safe() {
+            return Sharded::Shards(Box::new(
+                [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
+            ));
         }
-    }
 
-    #[inline(always)]
-    fn count(&self) -> usize {
-        // `self.mask` is always one below the used shard count
-        self.mask() + 1
+        Sharded::Single(Lock::new(value()))
     }
 
     /// The shard is selected by hashing `val` with `FxHasher`.
@@ -75,9 +54,24 @@ impl<T> Sharded<T> {
     }
 
     #[inline]
-    pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> {
-        // SAFETY: The index get ANDed with the mask, ensuring it is always inbounds.
-        unsafe { &self.shards.get_unchecked(i & self.mask()).0 }
+    pub fn get_shard_by_index(&self, _i: usize) -> &Lock<T> {
+        match self {
+            Self::Single(single) => &single,
+            #[cfg(parallel_compiler)]
+            Self::Shards(shards) => {
+                // SAFETY: The index gets ANDed with the shard mask, ensuring it is always inbounds.
+                unsafe { &shards.get_unchecked(_i & (SHARDS - 1)).0 }
+            }
+        }
+    }
+
+    #[inline]
+    fn count(&self) -> usize {
+        match self {
+            Self::Single(..) => 1,
+            #[cfg(parallel_compiler)]
+            Self::Shards(..) => SHARDS,
+        }
     }
 
     pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {