Use FxHashMap and FxHashSet in hot code paths

We can also use these maps and sets in place of `SeaHasher` because
they are also deterministic. Note that we're not swapping std's
`HashMap` and `HashSet` wholesale inside of `collections` because
on the server we need cryptographically secure collections.
This commit is contained in:
Antonio Scandurra 2023-12-12 13:35:22 +01:00
parent 385c830bef
commit b871f906d6
8 changed files with 40 additions and 52 deletions

2
Cargo.lock generated
View File

@ -1990,7 +1990,7 @@ dependencies = [
name = "collections" name = "collections"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"seahash", "rustc-hash",
] ]
[[package]] [[package]]

View File

@ -9,7 +9,7 @@ path = "src/collections.rs"
doctest = false doctest = false
[features] [features]
test-support = ["seahash"] test-support = []
[dependencies] [dependencies]
seahash = { version = "4.1", optional = true } rustc-hash = "1.1"

View File

@ -1,21 +1,8 @@
#[cfg(feature = "test-support")] #[cfg(feature = "test-support")]
#[derive(Clone, Default)] pub type HashMap<K, V> = FxHashMap<K, V>;
pub struct DeterministicState;
#[cfg(feature = "test-support")] #[cfg(feature = "test-support")]
impl std::hash::BuildHasher for DeterministicState { pub type HashSet<T> = FxHashSet<T>;
type Hasher = seahash::SeaHasher;
fn build_hasher(&self) -> Self::Hasher {
seahash::SeaHasher::new()
}
}
#[cfg(feature = "test-support")]
pub type HashMap<K, V> = std::collections::HashMap<K, V, DeterministicState>;
#[cfg(feature = "test-support")]
pub type HashSet<T> = std::collections::HashSet<T, DeterministicState>;
#[cfg(not(feature = "test-support"))] #[cfg(not(feature = "test-support"))]
pub type HashMap<K, V> = std::collections::HashMap<K, V>; pub type HashMap<K, V> = std::collections::HashMap<K, V>;
@ -23,6 +10,7 @@ pub type HashMap<K, V> = std::collections::HashMap<K, V>;
#[cfg(not(feature = "test-support"))] #[cfg(not(feature = "test-support"))]
pub type HashSet<T> = std::collections::HashSet<T>; pub type HashSet<T> = std::collections::HashSet<T>;
pub use rustc_hash::{FxHashMap, FxHashSet};
use std::any::TypeId; use std::any::TypeId;
pub use std::collections::*; pub use std::collections::*;

View File

@ -24,7 +24,7 @@ use crate::{
WindowContext, WindowHandle, WindowId, WindowContext, WindowHandle, WindowId,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::{HashMap, HashSet, VecDeque}; use collections::{FxHashMap, FxHashSet, VecDeque};
use futures::{channel::oneshot, future::LocalBoxFuture, Future}; use futures::{channel::oneshot, future::LocalBoxFuture, Future};
use parking_lot::Mutex; use parking_lot::Mutex;
use slotmap::SlotMap; use slotmap::SlotMap;
@ -191,24 +191,24 @@ pub struct AppContext {
pub(crate) actions: Rc<ActionRegistry>, pub(crate) actions: Rc<ActionRegistry>,
pub(crate) active_drag: Option<AnyDrag>, pub(crate) active_drag: Option<AnyDrag>,
pub(crate) active_tooltip: Option<AnyTooltip>, pub(crate) active_tooltip: Option<AnyTooltip>,
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>, pub(crate) next_frame_callbacks: FxHashMap<DisplayId, Vec<FrameCallback>>,
pub(crate) frame_consumers: HashMap<DisplayId, Task<()>>, pub(crate) frame_consumers: FxHashMap<DisplayId, Task<()>>,
pub(crate) background_executor: BackgroundExecutor, pub(crate) background_executor: BackgroundExecutor,
pub(crate) foreground_executor: ForegroundExecutor, pub(crate) foreground_executor: ForegroundExecutor,
pub(crate) svg_renderer: SvgRenderer, pub(crate) svg_renderer: SvgRenderer,
asset_source: Arc<dyn AssetSource>, asset_source: Arc<dyn AssetSource>,
pub(crate) image_cache: ImageCache, pub(crate) image_cache: ImageCache,
pub(crate) text_style_stack: Vec<TextStyleRefinement>, pub(crate) text_style_stack: Vec<TextStyleRefinement>,
pub(crate) globals_by_type: HashMap<TypeId, Box<dyn Any>>, pub(crate) globals_by_type: FxHashMap<TypeId, Box<dyn Any>>,
pub(crate) entities: EntityMap, pub(crate) entities: EntityMap,
pub(crate) new_view_observers: SubscriberSet<TypeId, NewViewListener>, pub(crate) new_view_observers: SubscriberSet<TypeId, NewViewListener>,
pub(crate) windows: SlotMap<WindowId, Option<Window>>, pub(crate) windows: SlotMap<WindowId, Option<Window>>,
pub(crate) keymap: Arc<Mutex<Keymap>>, pub(crate) keymap: Arc<Mutex<Keymap>>,
pub(crate) global_action_listeners: pub(crate) global_action_listeners:
HashMap<TypeId, Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>, FxHashMap<TypeId, Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
pending_effects: VecDeque<Effect>, pending_effects: VecDeque<Effect>,
pub(crate) pending_notifications: HashSet<EntityId>, pub(crate) pending_notifications: FxHashSet<EntityId>,
pub(crate) pending_global_notifications: HashSet<TypeId>, pub(crate) pending_global_notifications: FxHashSet<TypeId>,
pub(crate) observers: SubscriberSet<EntityId, Handler>, pub(crate) observers: SubscriberSet<EntityId, Handler>,
// TypeId is the type of the event that the listener callback expects // TypeId is the type of the event that the listener callback expects
pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>, pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
@ -253,23 +253,23 @@ impl AppContext {
pending_updates: 0, pending_updates: 0,
active_drag: None, active_drag: None,
active_tooltip: None, active_tooltip: None,
next_frame_callbacks: HashMap::default(), next_frame_callbacks: FxHashMap::default(),
frame_consumers: HashMap::default(), frame_consumers: FxHashMap::default(),
background_executor: executor, background_executor: executor,
foreground_executor, foreground_executor,
svg_renderer: SvgRenderer::new(asset_source.clone()), svg_renderer: SvgRenderer::new(asset_source.clone()),
asset_source, asset_source,
image_cache: ImageCache::new(http_client), image_cache: ImageCache::new(http_client),
text_style_stack: Vec::new(), text_style_stack: Vec::new(),
globals_by_type: HashMap::default(), globals_by_type: FxHashMap::default(),
entities, entities,
new_view_observers: SubscriberSet::new(), new_view_observers: SubscriberSet::new(),
windows: SlotMap::with_key(), windows: SlotMap::with_key(),
keymap: Arc::new(Mutex::new(Keymap::default())), keymap: Arc::new(Mutex::new(Keymap::default())),
global_action_listeners: HashMap::default(), global_action_listeners: FxHashMap::default(),
pending_effects: VecDeque::new(), pending_effects: VecDeque::new(),
pending_notifications: HashSet::default(), pending_notifications: FxHashSet::default(),
pending_global_notifications: HashSet::default(), pending_global_notifications: FxHashSet::default(),
observers: SubscriberSet::new(), observers: SubscriberSet::new(),
event_listeners: SubscriberSet::new(), event_listeners: SubscriberSet::new(),
release_listeners: SubscriberSet::new(), release_listeners: SubscriberSet::new(),

View File

@ -3,7 +3,7 @@ use crate::{
Point, Size, Point, Size,
}; };
use anyhow::Result; use anyhow::Result;
use collections::HashMap; use collections::FxHashMap;
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use etagere::BucketedAtlasAllocator; use etagere::BucketedAtlasAllocator;
use metal::Device; use metal::Device;
@ -53,7 +53,7 @@ struct MetalAtlasState {
monochrome_textures: Vec<MetalAtlasTexture>, monochrome_textures: Vec<MetalAtlasTexture>,
polychrome_textures: Vec<MetalAtlasTexture>, polychrome_textures: Vec<MetalAtlasTexture>,
path_textures: Vec<MetalAtlasTexture>, path_textures: Vec<MetalAtlasTexture>,
tiles_by_key: HashMap<AtlasKey, AtlasTile>, tiles_by_key: FxHashMap<AtlasKey, AtlasTile>,
} }
impl PlatformAtlas for MetalAtlas { impl PlatformAtlas for MetalAtlas {

View File

@ -2,7 +2,7 @@ use crate::{
AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style, AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style,
WindowContext, WindowContext,
}; };
use collections::{HashMap, HashSet}; use collections::{FxHashMap, FxHashSet};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt::Debug; use std::fmt::Debug;
use taffy::{ use taffy::{
@ -14,10 +14,10 @@ use taffy::{
pub struct TaffyLayoutEngine { pub struct TaffyLayoutEngine {
taffy: Taffy, taffy: Taffy,
children_to_parents: HashMap<LayoutId, LayoutId>, children_to_parents: FxHashMap<LayoutId, LayoutId>,
absolute_layout_bounds: HashMap<LayoutId, Bounds<Pixels>>, absolute_layout_bounds: FxHashMap<LayoutId, Bounds<Pixels>>,
computed_layouts: HashSet<LayoutId>, computed_layouts: FxHashSet<LayoutId>,
nodes_to_measure: HashMap< nodes_to_measure: FxHashMap<
LayoutId, LayoutId,
Box< Box<
dyn FnMut( dyn FnMut(
@ -36,10 +36,10 @@ impl TaffyLayoutEngine {
pub fn new() -> Self { pub fn new() -> Self {
TaffyLayoutEngine { TaffyLayoutEngine {
taffy: Taffy::new(), taffy: Taffy::new(),
children_to_parents: HashMap::default(), children_to_parents: FxHashMap::default(),
absolute_layout_bounds: HashMap::default(), absolute_layout_bounds: FxHashMap::default(),
computed_layouts: HashSet::default(), computed_layouts: FxHashSet::default(),
nodes_to_measure: HashMap::default(), nodes_to_measure: FxHashMap::default(),
} }
} }

View File

@ -13,7 +13,7 @@ use crate::{
UnderlineStyle, UnderlineStyle,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use collections::HashMap; use collections::FxHashMap;
use core::fmt; use core::fmt;
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -37,10 +37,10 @@ pub const SUBPIXEL_VARIANTS: u8 = 4;
pub struct TextSystem { pub struct TextSystem {
line_layout_cache: Arc<LineLayoutCache>, line_layout_cache: Arc<LineLayoutCache>,
platform_text_system: Arc<dyn PlatformTextSystem>, platform_text_system: Arc<dyn PlatformTextSystem>,
font_ids_by_font: RwLock<HashMap<Font, FontId>>, font_ids_by_font: RwLock<FxHashMap<Font, FontId>>,
font_metrics: RwLock<HashMap<FontId, FontMetrics>>, font_metrics: RwLock<FxHashMap<FontId, FontMetrics>>,
raster_bounds: RwLock<HashMap<RenderGlyphParams, Bounds<DevicePixels>>>, raster_bounds: RwLock<FxHashMap<RenderGlyphParams, Bounds<DevicePixels>>>,
wrapper_pool: Mutex<HashMap<FontIdWithSize, Vec<LineWrapper>>>, wrapper_pool: Mutex<FxHashMap<FontIdWithSize, Vec<LineWrapper>>>,
font_runs_pool: Mutex<Vec<Vec<FontRun>>>, font_runs_pool: Mutex<Vec<Vec<FontRun>>>,
} }

View File

@ -1,9 +1,9 @@
use crate::{px, FontId, GlyphId, Pixels, PlatformTextSystem, Point, Size}; use crate::{px, FontId, GlyphId, Pixels, PlatformTextSystem, Point, Size};
use collections::FxHashMap;
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
borrow::Borrow, borrow::Borrow,
collections::HashMap,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
sync::Arc, sync::Arc,
}; };
@ -236,10 +236,10 @@ impl WrappedLineLayout {
} }
pub(crate) struct LineLayoutCache { pub(crate) struct LineLayoutCache {
previous_frame: Mutex<HashMap<CacheKey, Arc<LineLayout>>>, previous_frame: Mutex<FxHashMap<CacheKey, Arc<LineLayout>>>,
current_frame: RwLock<HashMap<CacheKey, Arc<LineLayout>>>, current_frame: RwLock<FxHashMap<CacheKey, Arc<LineLayout>>>,
previous_frame_wrapped: Mutex<HashMap<CacheKey, Arc<WrappedLineLayout>>>, previous_frame_wrapped: Mutex<FxHashMap<CacheKey, Arc<WrappedLineLayout>>>,
current_frame_wrapped: RwLock<HashMap<CacheKey, Arc<WrappedLineLayout>>>, current_frame_wrapped: RwLock<FxHashMap<CacheKey, Arc<WrappedLineLayout>>>,
platform_text_system: Arc<dyn PlatformTextSystem>, platform_text_system: Arc<dyn PlatformTextSystem>,
} }