layout: Implement parallel reflow for the bubble-widths and

assign-heights phases.

This uses the new work-stealing deque. By default, 3/4 of a thread per
logical CPU is used. This can be tuned with the `-y` flag.

I measured a 65% reflow speedup on `perf-rainbow.html` and a 247% reflow
speedup on `http://en.wikipedia.org/wiki/South_China_Sea` on a 4-core
HyperThreaded Core i7. However, numbers were fairly volatile, especially
for the latter.
This commit is contained in:
Patrick Walton 2014-01-14 14:57:40 -08:00
parent 539cf58f73
commit 54f0f17f83
21 changed files with 706 additions and 141 deletions

View file

@ -26,7 +26,7 @@ use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBox
use layout::box_::{UnscannedTextBox, UnscannedTextBoxInfo, InlineInfo, InlineParentInfo};
use layout::context::LayoutContext;
use layout::float_context::FloatType;
use layout::flow::{BaseFlow, Flow, MutableFlowUtils};
use layout::flow::{BaseFlow, Flow, MutableOwnedFlowUtils};
use layout::inline::InlineFlow;
use layout::text::TextRunScanner;
use layout::util::LayoutDataAccess;
@ -173,8 +173,6 @@ impl<T> OptVector<T> for Option<~[T]> {
/// An object that knows how to create flows.
pub struct FlowConstructor<'a> {
/// The layout context.
///
/// FIXME(pcwalton): Why does this contain `@`??? That destroys parallelism!!!
layout_context: &'a mut LayoutContext,
/// The next flow ID to assign.
@ -207,7 +205,7 @@ impl<'fc> FlowConstructor<'fc> {
Some(url) => {
// FIXME(pcwalton): The fact that image boxes store the cache within them makes
// little sense to me.
Some(ImageBoxInfo::new(&node, url, self.layout_context.image_cache.clone()))
Some(ImageBoxInfo::new(&node, url, self.layout_context.shared.image_cache.clone()))
}
}
}
@ -236,9 +234,17 @@ impl<'fc> FlowConstructor<'fc> {
fn flush_inline_boxes_to_flow(&mut self, boxes: ~[Box], flow: &mut ~Flow, node: LayoutNode) {
if boxes.len() > 0 {
let inline_base = BaseFlow::new(self.next_flow_id(), node);
let mut inline_flow = ~InlineFlow::from_boxes(inline_base, boxes) as ~Flow;
self.layout_context.shared.leaf_set.access(|leaf_set| leaf_set.insert(&inline_flow));
TextRunScanner::new().scan_for_runs(self.layout_context, inline_flow);
flow.add_new_child(inline_flow)
let mut inline_flow = Some(inline_flow);
self.layout_context.shared.leaf_set.access(|leaf_set| {
flow.add_new_child(inline_flow.take_unwrap(), leaf_set)
})
}
}
@ -282,7 +288,10 @@ impl<'fc> FlowConstructor<'fc> {
self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow,
flow,
node);
flow.add_new_child(kid_flow);
let mut kid_flow = Some(kid_flow);
self.layout_context.shared.leaf_set.access(|leaf_set| {
flow.add_new_child(kid_flow.take_unwrap(), leaf_set)
})
}
ConstructionItemConstructionResult(InlineBoxesConstructionItem(
InlineBoxesConstructionResult {
@ -322,7 +331,10 @@ impl<'fc> FlowConstructor<'fc> {
// Push the flow generated by the {ib} split onto our list of
// flows.
flow.add_new_child(kid_flow);
let mut kid_flow = Some(kid_flow);
self.layout_context.shared.leaf_set.access(|leaf_set| {
flow.add_new_child(kid_flow.take_unwrap(), leaf_set)
})
}
}
}
@ -348,6 +360,9 @@ impl<'fc> FlowConstructor<'fc> {
let base = BaseFlow::new(self.next_flow_id(), node);
let box_ = self.build_box_for_node(node);
let mut flow = ~BlockFlow::from_box(base, box_, is_fixed) as ~Flow;
self.layout_context.shared.leaf_set.access(|leaf_set| leaf_set.insert(&flow));
self.build_children_of_block_flow(&mut flow, node);
flow
}
@ -358,7 +373,11 @@ impl<'fc> FlowConstructor<'fc> {
-> ~Flow {
let base = BaseFlow::new(self.next_flow_id(), node);
let box_ = self.build_box_for_node(node);
let mut flow = ~BlockFlow::float_from_box(base, float_type, box_) as ~Flow;
self.layout_context.shared.leaf_set.access(|leaf_set| leaf_set.insert(&flow));
self.build_children_of_block_flow(&mut flow, node);
flow
}