From 8eecefe4c87262c69f5f7fa0d623e08546a0fdde Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 6 Jun 2017 10:28:16 -0700 Subject: [PATCH 1/4] Make layout_thread debug logs less verbose --- components/layout_thread/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 9ddff21070e..bf6145b8e24 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1063,7 +1063,7 @@ impl LayoutThread { debug!("layout: processing reflow request for: {:?} ({}) (query={:?})", element, self.url, data.query_type); - debug!("{:?}", ShowSubtree(element.as_node())); + trace!("{:?}", ShowSubtree(element.as_node())); let initial_viewport = data.window_size.initial_viewport; let old_viewport_size = self.viewport_size; From a158b106f491fb64169789e30f0b1794fe9cfff1 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 6 Jun 2017 10:30:42 -0700 Subject: [PATCH 2/4] Don't spawn layout threads in sequential mode --- components/layout_thread/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index bf6145b8e24..89e4ff9f4aa 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -439,7 +439,11 @@ impl LayoutThread { let configuration = rayon::Configuration::new().num_threads(layout_threads); - let parallel_traversal = rayon::ThreadPool::new(configuration).ok(); + let parallel_traversal = if layout_threads > 1 { + Some(rayon::ThreadPool::new(configuration).expect("ThreadPool creation failed")) + } else { + None + }; debug!("Possible layout Threads: {}", layout_threads); // Create the channel on which new animations can be sent. From ea154d827859ad7b509c265789b1bc16571064c7 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 6 Jun 2017 10:36:01 -0700 Subject: [PATCH 3/4] Reduce parallel layout chunk size to 16 --- components/layout/parallel.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index ada231b8119..2d97c29d761 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -23,10 +23,7 @@ use traversal::AssignBSizes; pub use style::parallel::traverse_dom; /// Traversal chunk size. -/// -/// FIXME(bholley): This is all likely very inefficient and should probably be -/// reworked to mirror the style system's parallel.rs. -pub const CHUNK_SIZE: usize = 64; +const CHUNK_SIZE: usize = 16; #[allow(dead_code)] fn static_assertion(node: UnsafeNode) { From 7fd1626901af324f26208ceaba66e75c4d1c2154 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 6 Jun 2017 11:54:37 -0700 Subject: [PATCH 4/4] Reduce allocations during parallel layout --- components/layout/parallel.rs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index 2d97c29d761..713fdadcf38 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -14,6 +14,7 @@ use flow_ref::FlowRef; use profile_traits::time::{self, TimerMetadata, profile}; use rayon; use servo_config::opts; +use smallvec::SmallVec; use std::mem; use std::sync::atomic::{AtomicIsize, Ordering}; use style::dom::UnsafeNode; @@ -25,6 +26,8 @@ pub use style::parallel::traverse_dom; /// Traversal chunk size. const CHUNK_SIZE: usize = 16; +pub type FlowList = SmallVec<[UnsafeNode; CHUNK_SIZE]>; + #[allow(dead_code)] fn static_assertion(node: UnsafeNode) { unsafe { @@ -128,7 +131,7 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow], assign_isize_traversal: &'scope AssignISizes, assign_bsize_traversal: &'scope AssignBSizes) { - let mut discovered_child_flows = vec![]; + let mut discovered_child_flows = FlowList::new(); for unsafe_flow in unsafe_flows { let mut had_children = false; @@ -161,12 +164,29 @@ fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow], } } - for chunk in discovered_child_flows.chunks(CHUNK_SIZE) { - let nodes = chunk.iter().cloned().collect::>().into_boxed_slice(); + if discovered_child_flows.is_empty() { + return + } - scope.spawn(move |scope| { - top_down_flow(&nodes, scope, &assign_isize_traversal, &assign_bsize_traversal); - }); + if discovered_child_flows.len() <= CHUNK_SIZE { + // We can handle all the children in this work unit. + top_down_flow(&discovered_child_flows, + scope, + &assign_isize_traversal, + &assign_bsize_traversal); + } else { + // Spawn a new work unit for each chunk after the first. + let mut chunks = discovered_child_flows.chunks(CHUNK_SIZE); + let first_chunk = chunks.next(); + for chunk in chunks { + let nodes = chunk.iter().cloned().collect::(); + scope.spawn(move |scope| { + top_down_flow(&nodes, scope, &assign_isize_traversal, &assign_bsize_traversal); + }); + } + if let Some(chunk) = first_chunk { + top_down_flow(chunk, scope, &assign_isize_traversal, &assign_bsize_traversal); + } } } @@ -183,7 +203,7 @@ pub fn traverse_flow_tree_preorder( let assign_isize_traversal = &AssignISizes { layout_context: &context }; let assign_bsize_traversal = &AssignBSizes { layout_context: &context }; - let nodes = vec![borrowed_flow_to_unsafe_flow(root)].into_boxed_slice(); + let nodes = [borrowed_flow_to_unsafe_flow(root)]; queue.install(move || { rayon::scope(move |scope| {