From d67b21c0e9439f860ed42bba0737b1c429ded5d3 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 1 Feb 2023 20:45:11 -0600 Subject: [PATCH] improve performance --- packages/native-core/src/node_ref.rs | 4 +- packages/native-core/src/passes.rs | 98 ++++++++++++---------------- packages/native-core/src/real_dom.rs | 2 +- packages/native-core/src/tree.rs | 4 +- 4 files changed, 45 insertions(+), 63 deletions(-) diff --git a/packages/native-core/src/node_ref.rs b/packages/native-core/src/node_ref.rs index 12ac47f2b..f0e094cdd 100644 --- a/packages/native-core/src/node_ref.rs +++ b/packages/native-core/src/node_ref.rs @@ -10,12 +10,12 @@ use crate::{ #[derive(Debug)] pub struct NodeView<'a, V: FromAnyValue = ()> { inner: &'a NodeData, - mask: NodeMask, + mask: &'a NodeMask, } impl<'a, V: FromAnyValue> NodeView<'a, V> { /// Create a new NodeView from a VNode, and mask. - pub fn new(node: &'a NodeData, view: NodeMask) -> Self { + pub fn new(node: &'a NodeData, view: &'a NodeMask) -> Self { Self { inner: node, mask: view, diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 2ca7eab47..c5de9f965 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -1,7 +1,7 @@ use anymap::AnyMap; use core::panic; use parking_lot::RwLock; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; use std::any::{Any, TypeId}; use std::collections::BTreeMap; use std::marker::PhantomData; @@ -11,7 +11,7 @@ use crate::node::{FromAnyValue, NodeData}; use crate::node_ref::{NodeMaskBuilder, NodeView}; use crate::real_dom::RealDom; use crate::tree::{SlabEntry, Tree, TreeStateView}; -use crate::{FxDashMap, FxDashSet, SendAnyMap}; +use crate::{FxDashSet, SendAnyMap}; use crate::{NodeId, NodeMask}; #[derive(Default)] @@ -47,76 +47,58 @@ impl DirtyNodes { } } -#[derive(Default, Clone)] +#[derive(Clone)] pub struct DirtyNodeStates { - dirty: Arc>>>, + dirty: Arc>>>, } impl DirtyNodeStates { + pub fn with_passes(passes: impl Iterator) -> Self { + let mut dirty = FxHashMap::default(); + for pass in passes { + dirty.insert(pass, RwLock::new(BTreeMap::new())); + } + Self { + dirty: Arc::new(dirty), + } + } + pub fn insert(&self, pass_id: TypeId, node_id: NodeId, height: u16) { - let mut dirty = self.dirty.write(); - if let Some(dirty) = dirty.get_mut(&height) { - if let Some(mut entry) = dirty.get_mut(&pass_id) { - entry.add_node(node_id); - } else { - let mut entry = DirtyNodes::default(); - entry.add_node(node_id); - dirty.insert(pass_id, entry); - } + let btree = self.dirty.get(&pass_id).unwrap(); + let mut write = btree.write(); + if let Some(entry) = write.get_mut(&height) { + entry.add_node(node_id); } else { let mut entry = DirtyNodes::default(); entry.add_node(node_id); - let hm = FxDashMap::default(); - hm.insert(pass_id, entry); - dirty.insert(height, hm); + write.insert(height, entry); } } fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { - let dirty_read = self.dirty.read(); - let (&height, values) = dirty_read - .iter() - .find(|(_, values)| values.contains_key(&pass_id))?; - let node_id = { - let mut dirty = values.get_mut(&pass_id)?; - let node_id = dirty.pop()?; - if dirty.is_empty() { - drop(dirty); - values.remove(&pass_id); - } - node_id - }; - if values.is_empty() { - drop(dirty_read); - let mut dirty_write = self.dirty.write(); - dirty_write.remove(&height); + let mut values = self.dirty.get(&pass_id)?.write(); + let mut value = values.first_entry()?; + let height = *value.key(); + let ids = value.get_mut(); + let id = ids.pop()?; + if ids.is_empty() { + value.remove_entry(); } - Some((height, node_id)) + Some((height, id)) } fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { - let dirty_read = self.dirty.read(); - let (&height, values) = dirty_read - .iter() - .rev() - .find(|(_, values)| values.contains_key(&pass_id))?; - let node_id = { - let mut dirty = values.get_mut(&pass_id)?; - let node_id = dirty.pop()?; - if dirty.is_empty() { - drop(dirty); - values.remove(&pass_id); - } - node_id - }; - if values.is_empty() { - drop(dirty_read); - let mut dirty_write = self.dirty.write(); - dirty_write.remove(&height); + let mut values = self.dirty.get(&pass_id)?.write(); + let mut value = values.last_entry()?; + let height = *value.key(); + let ids = value.get_mut(); + let id = ids.pop()?; + if ids.is_empty() { + value.remove_entry(); } - Some((height, node_id)) + Some((height, id)) } } @@ -184,10 +166,10 @@ pub trait Pass: Any + Send + Sync { parent_dependant: !Self::parent_type_ids().is_empty(), child_dependant: !Self::child_type_ids().is_empty(), dependants: FxHashSet::default(), - mask: node_mask, + mask: node_mask.clone(), pass_direction: Self::pass_direction(), pass: Box::new( - |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| { + move |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| { debug_assert!(!Self::NodeDependencies::type_ids() .iter() .any(|id| *id == TypeId::of::())); @@ -203,7 +185,7 @@ pub trait Pass: Any + Send + Sync { if myself.value.is_none() { *myself.value = Some(Self::create( - NodeView::new(node_data, Self::NODE_MASK.build()), + NodeView::new(node_data, &node_mask), node, parent, children, @@ -212,7 +194,7 @@ pub trait Pass: Any + Send + Sync { true } else { myself.value.as_mut().unwrap().pass( - NodeView::new(node_data, Self::NODE_MASK.build()), + NodeView::new(node_data, &node_mask), node, parent, children, @@ -290,7 +272,7 @@ impl TypeErasedPass { nodes_updated.insert(id); for id in tree.children_ids(id).unwrap() { for dependant in &self.dependants { - dirty.insert(*dependant, id, height + 1); + dirty.insert(*dependant, *id, height + 1); } } } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 71dbf668e..b06119ff6 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -442,7 +442,7 @@ impl RealDom { ) -> (FxDashSet, FxHashMap) { let passes = std::mem::take(&mut self.passes_updated); let nodes_updated = std::mem::take(&mut self.nodes_updated); - let dirty_nodes = DirtyNodeStates::default(); + let dirty_nodes = DirtyNodeStates::with_passes(self.passes.iter().map(|p| p.this_type_id)); for (node_id, passes) in passes { // remove any nodes that were created and then removed in the same mutations from the dirty nodes list if let Some(height) = self.tree.height(node_id) { diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index ee2b03690..6d24ba83e 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -277,8 +277,8 @@ impl<'a, 'b> TreeStateView<'a, 'b> { }) } - pub fn children_ids(&self, id: NodeId) -> Option> { - self.nodes_data.get(id).map(|node| node.children.clone()) + pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { + self.nodes_data.get(id).map(|node| &*node.children) } pub fn parent_id(&self, id: NodeId) -> Option {