aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/parallel.rs296
1 files changed, 170 insertions, 126 deletions
diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs
index 6ff9acc19d5..879c2a1eea2 100644
--- a/components/layout/parallel.rs
+++ b/components/layout/parallel.rs
@@ -27,10 +27,13 @@ use std::sync::atomic::{AtomicIsize, Ordering};
use util::opts;
use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
+const CHUNK_SIZE: usize = 64;
+
#[allow(dead_code)]
fn static_assertion(node: UnsafeLayoutNode) {
unsafe {
let _: UnsafeFlow = ::std::intrinsics::transmute(node);
+ let _: UnsafeLayoutNodeList = ::std::intrinsics::transmute(node);
}
}
@@ -79,51 +82,74 @@ impl DomParallelInfo {
}
}
+pub type UnsafeLayoutNodeList = (Box<Vec<UnsafeLayoutNode>>, usize);
+
+pub type UnsafeFlowList = (Box<Vec<UnsafeLayoutNode>>, usize);
+
+pub type ChunkedDomTraversalFunction =
+ extern "Rust" fn(UnsafeLayoutNodeList,
+ &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>);
+
+pub type DomTraversalFunction =
+ extern "Rust" fn(UnsafeLayoutNode,
+ &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>);
+
+pub type ChunkedFlowTraversalFunction =
+ extern "Rust" fn(UnsafeFlowList, &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>);
+
pub type FlowTraversalFunction =
- extern "Rust" fn(UnsafeFlow, &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNode>);
+ extern "Rust" fn(UnsafeFlow, &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>);
/// A parallel top-down DOM traversal.
pub trait ParallelPreorderDomTraversal : PreorderDomTraversal {
fn run_parallel(&self,
- node: UnsafeLayoutNode,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNode>);
+ nodes: UnsafeLayoutNodeList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>);
#[inline(always)]
- fn run_parallel_helper(&self,
- unsafe_node: UnsafeLayoutNode,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNode>,
- top_down_func: FlowTraversalFunction,
- bottom_up_func: FlowTraversalFunction) {
- // Get a real layout node.
- let node: LayoutNode = unsafe {
- layout_node_from_unsafe_layout_node(&unsafe_node)
- };
-
- // Perform the appropriate traversal.
- self.process(node);
-
- // NB: O(n).
- let child_count = node.children().count();
-
- // Reset the count of children.
- {
- let mut layout_data_ref = node.mutate_layout_data();
- let layout_data = layout_data_ref.as_mut().expect("no layout data");
- layout_data.data.parallel.children_count.store(child_count as isize,
- Ordering::Relaxed);
- }
+ fn run_parallel_helper(
+ &self,
+ unsafe_nodes: UnsafeLayoutNodeList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>,
+ top_down_func: ChunkedDomTraversalFunction,
+ bottom_up_func: DomTraversalFunction) {
+ let mut discovered_child_nodes = Vec::new();
+ for unsafe_node in unsafe_nodes.0.into_iter() {
+ // Get a real layout node.
+ let node: LayoutNode = unsafe {
+ layout_node_from_unsafe_layout_node(&unsafe_node)
+ };
+
+ // Perform the appropriate traversal.
+ self.process(node);
+
+ // NB: O(n).
+ let child_count = node.children().count();
+
+ // Reset the count of children.
+ {
+ let mut layout_data_ref = node.mutate_layout_data();
+ let layout_data = layout_data_ref.as_mut().expect("no layout data");
+ layout_data.data.parallel.children_count.store(child_count as isize,
+ Ordering::Relaxed);
+ }
- // Possibly enqueue the children.
- if child_count != 0 {
- for kid in node.children() {
- proxy.push(WorkUnit {
- fun: top_down_func,
- data: layout_node_to_unsafe_layout_node(&kid),
- });
+ // Possibly enqueue the children.
+ if child_count != 0 {
+ for kid in node.children() {
+ discovered_child_nodes.push(layout_node_to_unsafe_layout_node(&kid))
+ }
+ } else {
+ // If there were no more children, start walking back up.
+ bottom_up_func(unsafe_node, proxy)
}
- } else {
- // If there were no more children, start walking back up.
- bottom_up_func(unsafe_node, proxy)
+ }
+
+ for chunk in discovered_child_nodes.chunks(CHUNK_SIZE) {
+ proxy.push(WorkUnit {
+ fun: top_down_func,
+ data: (box chunk.iter().cloned().collect(), 0),
+ });
}
}
}
@@ -143,14 +169,14 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal {
/// fetch-and-subtract the parent's children count.
fn run_parallel(&self,
mut unsafe_node: UnsafeLayoutNode,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNode>) {
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>) {
loop {
// Get a real layout node.
let node: LayoutNode = unsafe {
layout_node_from_unsafe_layout_node(&unsafe_node)
};
- // Perform the appropriate traversal.
+ // Perform the appropriate operation.
self.process(node);
let shared_layout_context = unsafe { &*(proxy.user_data().0) };
@@ -163,18 +189,17 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal {
unsafe {
let parent_layout_data =
- (*parent.borrow_layout_data_unchecked())
- .as_ref()
- .expect("no layout data");
+ (*parent.borrow_layout_data_unchecked()).as_ref().expect("no layout data");
unsafe_node = layout_node_to_unsafe_layout_node(&parent);
- let parent_layout_data: &LayoutDataWrapper = mem::transmute(parent_layout_data);
+ let parent_layout_data: &LayoutDataWrapper =
+ mem::transmute(parent_layout_data);
if parent_layout_data
.data
.parallel
.children_count
- .fetch_sub(1, Ordering::SeqCst) == 1 {
+ .fetch_sub(1, Ordering::Relaxed) == 1 {
// We were the last child of our parent. Construct flows for our parent.
} else {
// Get out of here and find another node to work on.
@@ -217,7 +242,7 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
/// fetch-and-subtract the parent's children count.
fn run_parallel(&self,
mut unsafe_flow: UnsafeFlow,
- _: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlow>) {
+ _: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) {
loop {
unsafe {
// Get a real flow.
@@ -247,7 +272,7 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
// on with our parent; otherwise, we've gotta wait.
let parent: &mut FlowRef = mem::transmute(&mut unsafe_parent);
let parent_base = flow::mut_base(&mut **parent);
- if parent_base.parallel.children_count.fetch_sub(1, Ordering::SeqCst) == 1 {
+ if parent_base.parallel.children_count.fetch_sub(1, Ordering::Relaxed) == 1 {
// We were the last child of our parent. Reflow our parent.
unsafe_flow = unsafe_parent
} else {
@@ -262,44 +287,51 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
/// A parallel top-down flow traversal.
trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
fn run_parallel(&self,
- unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlow>);
+ unsafe_flows: UnsafeFlowList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>);
fn should_record_thread_ids(&self) -> bool;
#[inline(always)]
fn run_parallel_helper(&self,
- mut unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlow>,
- top_down_func: FlowTraversalFunction,
+ unsafe_flows: UnsafeFlowList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>,
+ top_down_func: ChunkedFlowTraversalFunction,
bottom_up_func: FlowTraversalFunction) {
- let mut had_children = false;
- unsafe {
- // Get a real flow.
- let flow: &mut FlowRef = mem::transmute(&mut unsafe_flow);
+ let mut discovered_child_flows = Vec::new();
+ for mut unsafe_flow in unsafe_flows.0.into_iter() {
+ let mut had_children = false;
+ unsafe {
+ // Get a real flow.
+ let flow: &mut FlowRef = mem::transmute(&mut unsafe_flow);
- if self.should_record_thread_ids() {
- flow::mut_base(&mut **flow).thread_id = proxy.worker_index();
- }
+ if self.should_record_thread_ids() {
+ flow::mut_base(&mut **flow).thread_id = proxy.worker_index();
+ }
- if self.should_process(&mut **flow) {
- // Perform the appropriate traversal.
- self.process(&mut **flow);
+ if self.should_process(&mut **flow) {
+ // Perform the appropriate traversal.
+ self.process(&mut **flow);
+ }
+
+ // Possibly enqueue the children.
+ for kid in flow::child_iter(&mut **flow) {
+ had_children = true;
+ discovered_child_flows.push(borrowed_flow_to_unsafe_flow(kid));
+ }
}
- // Possibly enqueue the children.
- for kid in flow::child_iter(&mut **flow) {
- had_children = true;
- proxy.push(WorkUnit {
- fun: top_down_func,
- data: borrowed_flow_to_unsafe_flow(kid),
- });
+ // If there were no more children, start assigning block-sizes.
+ if !had_children {
+ bottom_up_func(unsafe_flow, proxy)
}
}
- // If there were no more children, start assigning block-sizes.
- if !had_children {
- bottom_up_func(unsafe_flow, proxy)
+ for chunk in discovered_child_flows.chunks(CHUNK_SIZE) {
+ proxy.push(WorkUnit {
+ fun: top_down_func,
+ data: (box chunk.iter().cloned().collect(), 0),
+ });
}
}
}
@@ -308,9 +340,9 @@ impl<'a> ParallelPostorderFlowTraversal for BubbleISizes<'a> {}
impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> {
fn run_parallel(&self,
- unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlow>) {
- self.run_parallel_helper(unsafe_flow,
+ unsafe_flows: UnsafeFlowList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) {
+ self.run_parallel_helper(unsafe_flows,
proxy,
assign_inline_sizes,
assign_block_sizes_and_store_overflow)
@@ -325,9 +357,9 @@ impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> {}
impl<'a> ParallelPreorderFlowTraversal for ComputeAbsolutePositions<'a> {
fn run_parallel(&self,
- unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlow>) {
- self.run_parallel_helper(unsafe_flow,
+ unsafe_flows: UnsafeFlowList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlowList>) {
+ self.run_parallel_helper(unsafe_flows,
proxy,
compute_absolute_positions,
build_display_list)
@@ -344,27 +376,24 @@ impl<'a> ParallelPostorderDomTraversal for ConstructFlows<'a> {}
impl <'a> ParallelPreorderDomTraversal for RecalcStyleForNode<'a> {
fn run_parallel(&self,
- unsafe_node: UnsafeLayoutNode,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNode>) {
- self.run_parallel_helper(unsafe_node,
- proxy,
- recalc_style,
- construct_flows)
+ unsafe_nodes: UnsafeLayoutNodeList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNodeList>) {
+ self.run_parallel_helper(unsafe_nodes, proxy, recalc_style, construct_flows)
}
}
-fn recalc_style(unsafe_node: UnsafeLayoutNode,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNode>) {
+fn recalc_style(unsafe_nodes: UnsafeLayoutNodeList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNodeList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) };
let layout_context = LayoutContext::new(shared_layout_context);
let recalc_style_for_node_traversal = RecalcStyleForNode {
layout_context: &layout_context,
};
- recalc_style_for_node_traversal.run_parallel(unsafe_node, proxy)
+ recalc_style_for_node_traversal.run_parallel(unsafe_nodes, proxy)
}
fn construct_flows(unsafe_node: UnsafeLayoutNode,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNode>) {
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNodeList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) };
let layout_context = LayoutContext::new(shared_layout_context);
let construct_flows_traversal = ConstructFlows {
@@ -373,18 +402,19 @@ fn construct_flows(unsafe_node: UnsafeLayoutNode,
construct_flows_traversal.run_parallel(unsafe_node, proxy)
}
-fn assign_inline_sizes(unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlow>) {
+fn assign_inline_sizes(unsafe_flows: UnsafeFlowList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) };
let layout_context = LayoutContext::new(shared_layout_context);
let assign_inline_sizes_traversal = AssignISizes {
layout_context: &layout_context,
};
- assign_inline_sizes_traversal.run_parallel(unsafe_flow, proxy)
+ assign_inline_sizes_traversal.run_parallel(unsafe_flows, proxy)
}
-fn assign_block_sizes_and_store_overflow(unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlow>) {
+fn assign_block_sizes_and_store_overflow(
+ unsafe_flow: UnsafeFlow,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) };
let layout_context = LayoutContext::new(shared_layout_context);
let assign_block_sizes_traversal = AssignBSizesAndStoreOverflow {
@@ -393,18 +423,19 @@ fn assign_block_sizes_and_store_overflow(unsafe_flow: UnsafeFlow,
assign_block_sizes_traversal.run_parallel(unsafe_flow, proxy)
}
-fn compute_absolute_positions(unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlow>) {
+fn compute_absolute_positions(
+ unsafe_flows: UnsafeFlowList,
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) };
let layout_context = LayoutContext::new(shared_layout_context);
let compute_absolute_positions_traversal = ComputeAbsolutePositions {
layout_context: &layout_context,
};
- compute_absolute_positions_traversal.run_parallel(unsafe_flow, proxy);
+ compute_absolute_positions_traversal.run_parallel(unsafe_flows, proxy);
}
fn build_display_list(unsafe_flow: UnsafeFlow,
- proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlow>) {
+ proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) };
let layout_context = LayoutContext::new(shared_layout_context);
@@ -415,26 +446,38 @@ fn build_display_list(unsafe_flow: UnsafeFlow,
build_display_list_traversal.run_parallel(unsafe_flow, proxy);
}
+fn run_queue_with_custom_work_data_type<To,F>(
+ queue: &mut WorkQueue<SharedLayoutContextWrapper,UnsafeLayoutNode>,
+ callback: F)
+ where To: 'static + Send, F: FnOnce(&mut WorkQueue<SharedLayoutContextWrapper,To>) {
+ unsafe {
+ let queue: &mut WorkQueue<SharedLayoutContextWrapper,To> = mem::transmute(queue);
+ callback(queue);
+ queue.run();
+ }
+}
+
pub fn traverse_dom_preorder(root: LayoutNode,
shared_layout_context: &SharedLayoutContext,
queue: &mut WorkQueue<SharedLayoutContextWrapper, UnsafeLayoutNode>) {
queue.data = SharedLayoutContextWrapper(shared_layout_context as *const _);
- queue.push(WorkUnit {
- fun: recalc_style,
- data: layout_node_to_unsafe_layout_node(&root),
+ run_queue_with_custom_work_data_type(queue, |queue| {
+ queue.push(WorkUnit {
+ fun: recalc_style,
+ data: (box vec![layout_node_to_unsafe_layout_node(&root)], 0),
+ });
});
- queue.run();
-
queue.data = SharedLayoutContextWrapper(ptr::null());
}
-pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
- profiler_metadata: ProfilerMetadata,
- time_profiler_chan: time::ProfilerChan,
- shared_layout_context: &SharedLayoutContext,
- queue: &mut WorkQueue<SharedLayoutContextWrapper,UnsafeFlow>) {
+pub fn traverse_flow_tree_preorder(
+ root: &mut FlowRef,
+ profiler_metadata: ProfilerMetadata,
+ time_profiler_chan: time::ProfilerChan,
+ shared_layout_context: &SharedLayoutContext,
+ queue: &mut WorkQueue<SharedLayoutContextWrapper,UnsafeLayoutNode>) {
if opts::get().bubble_inline_sizes_separately {
let layout_context = LayoutContext::new(shared_layout_context);
let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
@@ -443,35 +486,36 @@ pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
queue.data = SharedLayoutContextWrapper(shared_layout_context as *const _);
- profile(time::ProfilerCategory::LayoutParallelWarmup, profiler_metadata,
- time_profiler_chan, || {
- queue.push(WorkUnit {
- fun: assign_inline_sizes,
- data: mut_owned_flow_to_unsafe_flow(root),
- })
+ run_queue_with_custom_work_data_type(queue, |queue| {
+ profile(time::ProfilerCategory::LayoutParallelWarmup, profiler_metadata,
+ time_profiler_chan, || {
+ queue.push(WorkUnit {
+ fun: assign_inline_sizes,
+ data: (box vec![mut_owned_flow_to_unsafe_flow(root)], 0),
+ })
+ });
});
- queue.run();
-
queue.data = SharedLayoutContextWrapper(ptr::null())
}
-pub fn build_display_list_for_subtree(root: &mut FlowRef,
- profiler_metadata: ProfilerMetadata,
- time_profiler_chan: time::ProfilerChan,
- shared_layout_context: &SharedLayoutContext,
- queue: &mut WorkQueue<SharedLayoutContextWrapper,UnsafeFlow>) {
+pub fn build_display_list_for_subtree(
+ root: &mut FlowRef,
+ profiler_metadata: ProfilerMetadata,
+ time_profiler_chan: time::ProfilerChan,
+ shared_layout_context: &SharedLayoutContext,
+ queue: &mut WorkQueue<SharedLayoutContextWrapper,UnsafeLayoutNode>) {
queue.data = SharedLayoutContextWrapper(shared_layout_context as *const _);
- profile(time::ProfilerCategory::LayoutParallelWarmup, profiler_metadata,
- time_profiler_chan, || {
- queue.push(WorkUnit {
- fun: compute_absolute_positions,
- data: mut_owned_flow_to_unsafe_flow(root),
- })
+ run_queue_with_custom_work_data_type(queue, |queue| {
+ profile(time::ProfilerCategory::LayoutParallelWarmup, profiler_metadata,
+ time_profiler_chan, || {
+ queue.push(WorkUnit {
+ fun: compute_absolute_positions,
+ data: (box vec![mut_owned_flow_to_unsafe_flow(root)], 0),
+ })
+ });
});
- queue.run();
-
queue.data = SharedLayoutContextWrapper(ptr::null())
}