mirror of
https://github.com/servo/servo.git
synced 2025-06-20 23:28:59 +01:00
layout: Run assign-widths in parallel.
5% layout speedup on mobile Wikipedia.
This commit is contained in:
parent
df993fdaf3
commit
9479a7dcac
2 changed files with 97 additions and 29 deletions
|
@ -195,12 +195,14 @@ impl<'a> PostorderFlowTraversal for BubbleWidthsTraversal<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The assign-widths traversal. In Gecko this corresponds to `Reflow`.
|
/// 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> {
|
impl<'a> PreorderFlowTraversal for AssignWidthsTraversal<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||||
flow.assign_widths(**self);
|
flow.assign_widths(self.layout_context);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,7 +471,12 @@ impl LayoutTask {
|
||||||
// recompute them every time.
|
// recompute them every time.
|
||||||
// NOTE: this currently computes borders, so any pruning should separate that operation
|
// NOTE: this currently computes borders, so any pruning should separate that operation
|
||||||
// out.
|
// 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.
|
// 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.
|
/// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn solve_constraints_parallel(&mut self,
|
fn solve_constraints_parallel(&mut self,
|
||||||
layout_root: &mut Flow,
|
layout_root: &mut ~Flow,
|
||||||
layout_context: &mut LayoutContext) {
|
layout_context: &mut LayoutContext) {
|
||||||
match self.parallel_traversal {
|
match self.parallel_traversal {
|
||||||
None => fail!("solve_contraints_parallel() called with no parallel traversal ready"),
|
None => fail!("solve_contraints_parallel() called with no parallel traversal ready"),
|
||||||
Some(ref mut traversal) => {
|
Some(ref mut traversal) => {
|
||||||
parallel::traverse_flow_tree(BubbleWidthsTraversalKind,
|
parallel::traverse_flow_tree_postorder(BubbleWidthsTraversalKind,
|
||||||
&self.flow_leaf_set,
|
&self.flow_leaf_set,
|
||||||
self.profiler_chan.clone(),
|
self.profiler_chan.clone(),
|
||||||
layout_context,
|
layout_context,
|
||||||
|
@ -499,11 +506,12 @@ impl LayoutTask {
|
||||||
|
|
||||||
// NOTE: this currently computes borders, so any pruning should separate that
|
// NOTE: this currently computes borders, so any pruning should separate that
|
||||||
// operation out.
|
// operation out.
|
||||||
// TODO(pcwalton): Run this in parallel as well. This will require a bit more work
|
parallel::traverse_flow_tree_preorder(layout_root,
|
||||||
// because this is a top-down traversal, unlike the others.
|
self.profiler_chan.clone(),
|
||||||
layout_root.traverse_preorder(&mut AssignWidthsTraversal(layout_context));
|
layout_context,
|
||||||
|
traversal);
|
||||||
|
|
||||||
parallel::traverse_flow_tree(AssignHeightsAndStoreOverflowTraversalKind,
|
parallel::traverse_flow_tree_postorder(AssignHeightsAndStoreOverflowTraversalKind,
|
||||||
&self.flow_leaf_set,
|
&self.flow_leaf_set,
|
||||||
self.profiler_chan.clone(),
|
self.profiler_chan.clone(),
|
||||||
layout_context,
|
layout_context,
|
||||||
|
@ -624,7 +632,7 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
// Parallel mode.
|
// Parallel mode.
|
||||||
self.solve_constraints_parallel(layout_root, &mut layout_ctx)
|
self.solve_constraints_parallel(&mut layout_root, &mut layout_ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
use css::matching::{ApplicableDeclarations, CannotShare, MatchMethods, StyleWasShared};
|
use css::matching::{ApplicableDeclarations, CannotShare, MatchMethods, StyleWasShared};
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::extra::LayoutAuxMethods;
|
use layout::extra::LayoutAuxMethods;
|
||||||
use layout::flow::{Flow, FlowLeafSet, PostorderFlowTraversal};
|
use layout::flow::{Flow, FlowLeafSet, PreorderFlowTraversal, PostorderFlowTraversal};
|
||||||
use layout::flow;
|
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::util::{LayoutDataAccess, OpaqueNode};
|
||||||
use layout::wrapper::{layout_node_to_unsafe_layout_node, LayoutNode, UnsafeLayoutNode};
|
use layout::wrapper::{layout_node_to_unsafe_layout_node, LayoutNode, UnsafeLayoutNode};
|
||||||
|
|
||||||
|
@ -122,7 +123,9 @@ impl FlowParallelInfo {
|
||||||
|
|
||||||
/// A parallel bottom-up flow traversal.
|
/// A parallel bottom-up flow traversal.
|
||||||
trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
|
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 {
|
loop {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Get a real flow.
|
// 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> ParallelPostorderFlowTraversal for BubbleWidthsTraversal<'a> {}
|
||||||
|
|
||||||
|
impl<'a> ParallelPreorderFlowTraversal for AssignWidthsTraversal<'a> {}
|
||||||
|
|
||||||
impl<'a> ParallelPostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {}
|
impl<'a> ParallelPostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {}
|
||||||
|
|
||||||
fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
|
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 {
|
let layout_context: &mut LayoutContext = unsafe {
|
||||||
cast::transmute(*proxy.user_data())
|
cast::transmute(*proxy.user_data())
|
||||||
};
|
};
|
||||||
let mut bubble_widths_traversal = BubbleWidthsTraversal {
|
let mut bubble_widths_traversal = BubbleWidthsTraversal {
|
||||||
layout_context: layout_context,
|
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,
|
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 {
|
let mut assign_heights_traversal = AssignHeightsAndStoreOverflowTraversal {
|
||||||
layout_context: layout_context,
|
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,
|
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()
|
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>,
|
leaf_set: &Arc<FlowLeafSet>,
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
layout_context: &mut LayoutContext,
|
layout_context: &mut LayoutContext,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue