diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2014-02-14 18:18:48 -0800 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2014-02-24 18:06:24 -0800 |
commit | 9479a7dcac09dcb370af76b12d532f5f46e69e1c (patch) | |
tree | 958f5a7f96d3f5682d06206365997a744d310f0e /src/components/main/layout | |
parent | df993fdaf3c1c031154389a0832914d133bc722a (diff) | |
download | servo-9479a7dcac09dcb370af76b12d532f5f46e69e1c.tar.gz servo-9479a7dcac09dcb370af76b12d532f5f46e69e1c.zip |
layout: Run assign-widths in parallel.
5% layout speedup on mobile Wikipedia.
Diffstat (limited to 'src/components/main/layout')
-rw-r--r-- | src/components/main/layout/layout_task.rs | 46 | ||||
-rw-r--r-- | src/components/main/layout/parallel.rs | 82 |
2 files changed, 98 insertions, 30 deletions
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 70abe34b82c..91df36db999 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -195,12 +195,14 @@ impl<'a> PostorderFlowTraversal for BubbleWidthsTraversal<'a> { } /// The assign-widths traversal. In Gecko this corresponds to `Reflow`. -struct AssignWidthsTraversal<'a>(&'a mut LayoutContext); +pub struct AssignWidthsTraversal<'a> { + layout_context: &'a mut LayoutContext, +} impl<'a> PreorderFlowTraversal for AssignWidthsTraversal<'a> { #[inline] fn process(&mut self, flow: &mut Flow) -> bool { - flow.assign_widths(**self); + flow.assign_widths(self.layout_context); true } } @@ -469,7 +471,12 @@ impl LayoutTask { // recompute them every time. // NOTE: this currently computes borders, so any pruning should separate that operation // out. - layout_root.traverse_preorder(&mut AssignWidthsTraversal(layout_context)); + { + let mut traversal = AssignWidthsTraversal { + layout_context: layout_context, + }; + layout_root.traverse_preorder(&mut traversal); + } // FIXME(pcwalton): Prune this pass as well. { @@ -486,28 +493,29 @@ impl LayoutTask { /// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling. #[inline(never)] fn solve_constraints_parallel(&mut self, - layout_root: &mut Flow, + layout_root: &mut ~Flow, layout_context: &mut LayoutContext) { match self.parallel_traversal { None => fail!("solve_contraints_parallel() called with no parallel traversal ready"), Some(ref mut traversal) => { - parallel::traverse_flow_tree(BubbleWidthsTraversalKind, - &self.flow_leaf_set, - self.profiler_chan.clone(), - layout_context, - traversal); + parallel::traverse_flow_tree_postorder(BubbleWidthsTraversalKind, + &self.flow_leaf_set, + self.profiler_chan.clone(), + layout_context, + traversal); // NOTE: this currently computes borders, so any pruning should separate that // operation out. - // TODO(pcwalton): Run this in parallel as well. This will require a bit more work - // because this is a top-down traversal, unlike the others. - layout_root.traverse_preorder(&mut AssignWidthsTraversal(layout_context)); - - parallel::traverse_flow_tree(AssignHeightsAndStoreOverflowTraversalKind, - &self.flow_leaf_set, - self.profiler_chan.clone(), - layout_context, - traversal); + parallel::traverse_flow_tree_preorder(layout_root, + self.profiler_chan.clone(), + layout_context, + traversal); + + parallel::traverse_flow_tree_postorder(AssignHeightsAndStoreOverflowTraversalKind, + &self.flow_leaf_set, + self.profiler_chan.clone(), + layout_context, + traversal); } } } @@ -624,7 +632,7 @@ impl LayoutTask { } Some(_) => { // Parallel mode. - self.solve_constraints_parallel(layout_root, &mut layout_ctx) + self.solve_constraints_parallel(&mut layout_root, &mut layout_ctx) } } }); diff --git a/src/components/main/layout/parallel.rs b/src/components/main/layout/parallel.rs index f601c3a5dd7..ecee2e2e8b4 100644 --- a/src/components/main/layout/parallel.rs +++ b/src/components/main/layout/parallel.rs @@ -9,9 +9,10 @@ use css::matching::{ApplicableDeclarations, CannotShare, MatchMethods, StyleWasShared}; use layout::context::LayoutContext; use layout::extra::LayoutAuxMethods; -use layout::flow::{Flow, FlowLeafSet, PostorderFlowTraversal}; +use layout::flow::{Flow, FlowLeafSet, PreorderFlowTraversal, PostorderFlowTraversal}; use layout::flow; -use layout::layout_task::{AssignHeightsAndStoreOverflowTraversal, BubbleWidthsTraversal}; +use layout::layout_task::{AssignHeightsAndStoreOverflowTraversal, AssignWidthsTraversal}; +use layout::layout_task::{BubbleWidthsTraversal}; use layout::util::{LayoutDataAccess, OpaqueNode}; use layout::wrapper::{layout_node_to_unsafe_layout_node, LayoutNode, UnsafeLayoutNode}; @@ -122,7 +123,9 @@ impl FlowParallelInfo { /// A parallel bottom-up flow traversal. trait ParallelPostorderFlowTraversal : PostorderFlowTraversal { - fn run_parallel(&mut self, mut unsafe_flow: UnsafeFlow) { + fn run_parallel(&mut self, + mut unsafe_flow: UnsafeFlow, + _: &mut WorkerProxy<*mut LayoutContext,PaddedUnsafeFlow>) { loop { unsafe { // Get a real flow. @@ -161,8 +164,33 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal { } } +/// A parallel top-down flow traversal. +trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { + fn run_parallel(&mut self, + unsafe_flow: UnsafeFlow, + proxy: &mut WorkerProxy<*mut LayoutContext,PaddedUnsafeFlow>) { + unsafe { + // Get a real flow. + let flow: &mut ~Flow = cast::transmute(&unsafe_flow); + + // Perform the appropriate traversal. + self.process(*flow); + + // Possibly enqueue the children. + for kid in flow::child_iter(*flow) { + proxy.push(WorkUnit { + fun: assign_widths, + data: UnsafeFlowConversions::from_flow(&borrowed_flow_to_unsafe_flow(kid)), + }); + } + } + } +} + impl<'a> ParallelPostorderFlowTraversal for BubbleWidthsTraversal<'a> {} +impl<'a> ParallelPreorderFlowTraversal for AssignWidthsTraversal<'a> {} + impl<'a> ParallelPostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {} fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode, @@ -245,14 +273,26 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode, } } -fn bubble_widths(unsafe_flow: PaddedUnsafeFlow, proxy: &mut WorkerProxy<*mut LayoutContext,PaddedUnsafeFlow>) { +fn bubble_widths(unsafe_flow: PaddedUnsafeFlow, + proxy: &mut WorkerProxy<*mut LayoutContext,PaddedUnsafeFlow>) { let layout_context: &mut LayoutContext = unsafe { cast::transmute(*proxy.user_data()) }; let mut bubble_widths_traversal = BubbleWidthsTraversal { layout_context: layout_context, }; - bubble_widths_traversal.run_parallel(unsafe_flow.to_flow()) + bubble_widths_traversal.run_parallel(unsafe_flow.to_flow(), proxy) +} + +fn assign_widths(unsafe_flow: PaddedUnsafeFlow, + proxy: &mut WorkerProxy<*mut LayoutContext,PaddedUnsafeFlow>) { + let layout_context: &mut LayoutContext = unsafe { + cast::transmute(*proxy.user_data()) + }; + let mut assign_widths_traversal = AssignWidthsTraversal { + layout_context: layout_context, + }; + assign_widths_traversal.run_parallel(unsafe_flow.to_flow(), proxy) } fn assign_heights_and_store_overflow(unsafe_flow: PaddedUnsafeFlow, @@ -263,7 +303,7 @@ fn assign_heights_and_store_overflow(unsafe_flow: PaddedUnsafeFlow, let mut assign_heights_traversal = AssignHeightsAndStoreOverflowTraversal { layout_context: layout_context, }; - assign_heights_traversal.run_parallel(unsafe_flow.to_flow()) + assign_heights_traversal.run_parallel(unsafe_flow.to_flow(), proxy) } pub fn match_and_cascade_subtree(root_node: &LayoutNode, @@ -284,11 +324,31 @@ pub fn match_and_cascade_subtree(root_node: &LayoutNode, queue.data = ptr::mut_null() } -pub fn traverse_flow_tree(kind: TraversalKind, - leaf_set: &Arc<FlowLeafSet>, - profiler_chan: ProfilerChan, - layout_context: &mut LayoutContext, - queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) { +pub fn traverse_flow_tree_preorder(root: &mut ~Flow, + profiler_chan: ProfilerChan, + layout_context: &mut LayoutContext, + queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) { + unsafe { + queue.data = cast::transmute(layout_context) + } + + profile(time::LayoutParallelWarmupCategory, profiler_chan, || { + queue.push(WorkUnit { + fun: assign_widths, + data: UnsafeFlowConversions::from_flow(&mut_owned_flow_to_unsafe_flow(root)), + }) + }); + + queue.run(); + + queue.data = ptr::mut_null() +} + +pub fn traverse_flow_tree_postorder(kind: TraversalKind, + leaf_set: &Arc<FlowLeafSet>, + profiler_chan: ProfilerChan, + layout_context: &mut LayoutContext, + queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) { unsafe { queue.data = cast::transmute(layout_context) } |