layout: Run assign-widths in parallel.

5% layout speedup on mobile Wikipedia.
This commit is contained in:
Patrick Walton 2014-02-14 18:18:48 -08:00
parent df993fdaf3
commit 9479a7dcac
2 changed files with 97 additions and 29 deletions

View file

@ -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,12 +493,12 @@ 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,
parallel::traverse_flow_tree_postorder(BubbleWidthsTraversalKind,
&self.flow_leaf_set,
self.profiler_chan.clone(),
layout_context,
@ -499,11 +506,12 @@ impl LayoutTask {
// 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_preorder(layout_root,
self.profiler_chan.clone(),
layout_context,
traversal);
parallel::traverse_flow_tree(AssignHeightsAndStoreOverflowTraversalKind,
parallel::traverse_flow_tree_postorder(AssignHeightsAndStoreOverflowTraversalKind,
&self.flow_leaf_set,
self.profiler_chan.clone(),
layout_context,
@ -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)
}
}
});

View file

@ -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,7 +324,27 @@ pub fn match_and_cascade_subtree(root_node: &LayoutNode,
queue.data = ptr::mut_null()
}
pub fn traverse_flow_tree(kind: TraversalKind,
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,