aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/main/layout
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-02-14 18:18:48 -0800
committerPatrick Walton <pcwalton@mimiga.net>2014-02-24 18:06:24 -0800
commit9479a7dcac09dcb370af76b12d532f5f46e69e1c (patch)
tree958f5a7f96d3f5682d06206365997a744d310f0e /src/components/main/layout
parentdf993fdaf3c1c031154389a0832914d133bc722a (diff)
downloadservo-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.rs46
-rw-r--r--src/components/main/layout/parallel.rs82
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)
}