From 92a0668c20b8dea00d8739dce2243113f518b427 Mon Sep 17 00:00:00 2001 From: Valerii Lashmanov Date: Sun, 27 Sep 2020 23:48:19 -0500 Subject: [PATCH] SsoHashMap minor refactoring, SSO_ARRAY_SIZE introduced --- compiler/rustc_data_structures/src/sso/map.rs | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 3089f887845..f466796100c 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -7,6 +7,25 @@ use std::hash::Hash; use std::iter::FromIterator; use std::ops::Index; +// For pointer-sized arguments arrays +// are faster than set/map for up to 64 +// arguments. +// +// On the other hand such a big array +// hurts cache performance, makes passing +// sso structures around very expensive. +// +// Biggest performance benefit is gained +// for reasonably small arrays that stay +// small in vast majority of cases. +// +// '8' is choosen as a sane default, to be +// reevaluated later. +// +// Note: As of now ArrayVec design prevents +// us from making it user-customizable. +const SSO_ARRAY_SIZE: usize = 8; + /// Small-storage-optimized implementation of a map. /// /// Stores elements in a small array up to a certain length @@ -26,7 +45,7 @@ use std::ops::Index; /// Vacant/Occupied entries and related #[derive(Clone)] pub enum SsoHashMap { - Array(ArrayVec<[(K, V); 8]>), + Array(ArrayVec<[(K, V); SSO_ARRAY_SIZE]>), Map(FxHashMap), } @@ -39,9 +58,8 @@ impl SsoHashMap { /// Creates an empty `SsoHashMap` with the specified capacity. pub fn with_capacity(cap: usize) -> Self { - let array = ArrayVec::new(); - if array.capacity() >= cap { - SsoHashMap::Array(array) + if cap <= SSO_ARRAY_SIZE { + Self::new() } else { SsoHashMap::Map(FxHashMap::with_capacity_and_hasher(cap, Default::default())) } @@ -59,7 +77,7 @@ impl SsoHashMap { /// Returns the number of elements the map can hold without reallocating. pub fn capacity(&self) -> usize { match self { - SsoHashMap::Array(array) => array.capacity(), + SsoHashMap::Array(_) => SSO_ARRAY_SIZE, SsoHashMap::Map(map) => map.capacity(), } } @@ -149,7 +167,7 @@ impl SsoHashMap { pub fn reserve(&mut self, additional: usize) { match self { SsoHashMap::Array(array) => { - if array.capacity() < (array.len() + additional) { + if SSO_ARRAY_SIZE < (array.len() + additional) { let mut map: FxHashMap = array.drain(..).collect(); map.reserve(additional); *self = SsoHashMap::Map(map); @@ -164,10 +182,8 @@ impl SsoHashMap { /// and possibly leaving some space in accordance with the resize policy. pub fn shrink_to_fit(&mut self) { if let SsoHashMap::Map(map) = self { - let mut array = ArrayVec::new(); - if map.len() <= array.capacity() { - array.extend(map.drain()); - *self = SsoHashMap::Array(array); + if map.len() <= SSO_ARRAY_SIZE { + *self = SsoHashMap::Array(map.drain().collect()); } else { map.shrink_to_fit(); } @@ -361,7 +377,7 @@ impl Extend<(K, V)> for SsoHashMap { fn extend_reserve(&mut self, additional: usize) { match self { SsoHashMap::Array(array) => { - if array.capacity() < (array.len() + additional) { + if SSO_ARRAY_SIZE < (array.len() + additional) { let mut map: FxHashMap = array.drain(..).collect(); map.extend_reserve(additional); *self = SsoHashMap::Map(map); @@ -517,8 +533,9 @@ impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { let index = if let Some(index) = found_index { index } else { + let index = array.len(); array.try_push((self.key, default())).unwrap(); - array.len() - 1 + index }; &mut array[index].1 }