aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/parallel.rs
diff options
context:
space:
mode:
authorPu Xingyu <pu.stshine@gmail.com>2017-02-07 10:45:13 +0800
committerPu Xingyu <pu.stshine@gmail.com>2017-02-08 08:47:54 +0800
commit336aa795b4b9933436c9df0200de64e18b6f3b7e (patch)
tree7b8acf2d9eba39a68d47205462b0b29633584a28 /components/layout/parallel.rs
parentf07bfaa97466018f93124e308556aa93293cf648 (diff)
downloadservo-336aa795b4b9933436c9df0200de64e18b6f3b7e.tar.gz
servo-336aa795b4b9933436c9df0200de64e18b6f3b7e.zip
Remove cached thread local context from LayoutContext
Remove cached thread local context from LayoutContext, use LayoutContext for assign_inline_sizes(), and simplify the parallel flow traversal code.
Diffstat (limited to 'components/layout/parallel.rs')
-rw-r--r--components/layout/parallel.rs232
1 files changed, 86 insertions, 146 deletions
diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs
index a51f585eb3c..6128abbdae6 100644
--- a/components/layout/parallel.rs
+++ b/components/layout/parallel.rs
@@ -8,7 +8,7 @@
#![allow(unsafe_code)]
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
use flow::{self, Flow, MutableFlowUtils, PostorderFlowTraversal, PreorderFlowTraversal};
use flow_ref::FlowRef;
use profile_traits::time::{self, TimerMetadata, profile};
@@ -49,11 +49,6 @@ pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow {
}
}
-pub type ChunkedFlowTraversalFunction<'scope> =
- extern "Rust" fn(Box<[UnsafeFlow]>, &rayon::Scope<'scope>, &'scope SharedLayoutContext);
-
-pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &LayoutContext);
-
/// Information that we need stored in each flow.
pub struct FlowParallelInfo {
/// The number of children that still need work done.
@@ -71,183 +66,128 @@ impl FlowParallelInfo {
}
}
-/// A parallel bottom-up flow traversal.
-trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
- /// Process current flow and potentially traverse its ancestors.
- ///
- /// If we are the last child that finished processing, recursively process
- /// our parent. Else, stop. Also, stop at the root.
- ///
- /// Thus, if we start with all the leaves of a tree, we end up traversing
- /// the whole tree bottom-up because each parent will be processed exactly
- /// once (by the last child that finishes processing).
- ///
- /// The only communication between siblings is that they both
- /// fetch-and-subtract the parent's children count.
- fn run_parallel(&self, mut unsafe_flow: UnsafeFlow) {
- loop {
- // Get a real flow.
- let flow: &mut Flow = unsafe {
- mem::transmute(unsafe_flow)
- };
-
- // Perform the appropriate traversal.
- if self.should_process(flow) {
- self.process(flow);
- }
+/// Process current flow and potentially traverse its ancestors.
+///
+/// If we are the last child that finished processing, recursively process
+/// our parent. Else, stop. Also, stop at the root.
+///
+/// Thus, if we start with all the leaves of a tree, we end up traversing
+/// the whole tree bottom-up because each parent will be processed exactly
+/// once (by the last child that finishes processing).
+///
+/// The only communication between siblings is that they both
+/// fetch-and-subtract the parent's children count.
+fn buttom_up_flow(mut unsafe_flow: UnsafeFlow,
+ assign_bsize_traversal: &AssignBSizes) {
+ loop {
+ // Get a real flow.
+ let flow: &mut Flow = unsafe {
+ mem::transmute(unsafe_flow)
+ };
+
+ // Perform the appropriate traversal.
+ if assign_bsize_traversal.should_process(flow) {
+ assign_bsize_traversal.process(flow);
+ }
- let base = flow::mut_base(flow);
+ let base = flow::mut_base(flow);
- // Reset the count of children for the next layout traversal.
- base.parallel.children_count.store(base.children.len() as isize,
- Ordering::Relaxed);
+ // Reset the count of children for the next layout traversal.
+ base.parallel.children_count.store(base.children.len() as isize,
+ Ordering::Relaxed);
- // Possibly enqueue the parent.
- let unsafe_parent = base.parallel.parent;
- if unsafe_parent == null_unsafe_flow() {
- // We're done!
- break
- }
+ // Possibly enqueue the parent.
+ let unsafe_parent = base.parallel.parent;
+ if unsafe_parent == null_unsafe_flow() {
+ // We're done!
+ break
+ }
- // No, we're not at the root yet. Then are we the last child
- // of our parent to finish processing? If so, we can continue
- // on with our parent; otherwise, we've gotta wait.
- let parent: &mut Flow = unsafe {
- mem::transmute(unsafe_parent)
- };
- let parent_base = flow::mut_base(parent);
- 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 {
- // Stop.
- break
- }
+ // No, we're not at the root yet. Then are we the last child
+ // of our parent to finish processing? If so, we can continue
+ // on with our parent; otherwise, we've gotta wait.
+ let parent: &mut Flow = unsafe {
+ mem::transmute(unsafe_parent)
+ };
+ let parent_base = flow::mut_base(parent);
+ 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 {
+ // Stop.
+ break
}
}
}
-/// A parallel top-down flow traversal.
-trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
- fn run_parallel<'scope>(&self,
- unsafe_flows: &[UnsafeFlow],
- scope: &rayon::Scope<'scope>,
- shared: &'scope SharedLayoutContext);
-
- fn should_record_thread_ids(&self) -> bool;
-
- #[inline(always)]
- fn run_parallel_helper<'scope>(&self,
- unsafe_flows: &[UnsafeFlow],
- scope: &rayon::Scope<'scope>,
- shared: &'scope SharedLayoutContext,
- top_down_func: ChunkedFlowTraversalFunction<'scope>,
- bottom_up_func: FlowTraversalFunction)
- {
- let mut discovered_child_flows = vec![];
- let context = LayoutContext::new(&shared);
-
- for unsafe_flow in unsafe_flows {
- let mut had_children = false;
- unsafe {
- // Get a real flow.
- let flow: &mut Flow = mem::transmute(*unsafe_flow);
-
- if self.should_record_thread_ids() {
- // FIXME(emilio): With the switch to rayon we can no longer
- // access a thread id from here easily. Either instrument
- // rayon (the unstable feature) to get a worker thread
- // identifier, or remove all the layout tinting mode.
- //
- // flow::mut_base(flow).thread_id = proxy.worker_index();
- }
-
- if self.should_process(flow) {
- // Perform the appropriate traversal.
- self.process(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));
- }
+fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
+ scope: &rayon::Scope<'scope>,
+ assign_isize_traversal: &'scope AssignISizes,
+ assign_bsize_traversal: &'scope AssignBSizes)
+{
+ let mut discovered_child_flows = vec![];
+
+ for unsafe_flow in unsafe_flows {
+ let mut had_children = false;
+ unsafe {
+ // Get a real flow.
+ let flow: &mut Flow = mem::transmute(*unsafe_flow);
+
+ // FIXME(emilio): With the switch to rayon we can no longer
+ // access a thread id from here easily. Either instrument
+ // rayon (the unstable feature) to get a worker thread
+ // identifier, or remove all the layout tinting mode.
+ //
+ // flow::mut_base(flow).thread_id = proxy.worker_index();
+
+ if assign_isize_traversal.should_process(flow) {
+ // Perform the appropriate traversal.
+ assign_isize_traversal.process(flow);
}
- // If there were no more children, start assigning block-sizes.
- if !had_children {
- bottom_up_func(*unsafe_flow, &context)
+ // 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));
}
}
- for chunk in discovered_child_flows.chunks(CHUNK_SIZE) {
- let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();
-
- scope.spawn(move |scope| {
- top_down_func(nodes, scope, shared);
- });
+ // If there were no more children, start assigning block-sizes.
+ if !had_children {
+ buttom_up_flow(*unsafe_flow, &assign_bsize_traversal)
}
}
-}
-impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> {
- fn run_parallel<'scope>(&self,
- unsafe_flows: &[UnsafeFlow],
- scope: &rayon::Scope<'scope>,
- shared: &'scope SharedLayoutContext)
- {
- self.run_parallel_helper(unsafe_flows,
- scope,
- shared,
- assign_inline_sizes,
- assign_block_sizes_and_store_overflow)
- }
+ for chunk in discovered_child_flows.chunks(CHUNK_SIZE) {
+ let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();
- fn should_record_thread_ids(&self) -> bool {
- true
+ scope.spawn(move |scope| {
+ top_down_flow(&nodes, scope, &assign_isize_traversal, &assign_bsize_traversal);
+ });
}
}
-impl<'a> ParallelPostorderFlowTraversal for AssignBSizes<'a> {}
-
-fn assign_inline_sizes<'scope>(unsafe_flows: Box<[UnsafeFlow]>,
- scope: &rayon::Scope<'scope>,
- shared: &'scope SharedLayoutContext) {
- let assign_inline_sizes_traversal = AssignISizes {
- shared_context: &shared.style_context,
- };
- assign_inline_sizes_traversal.run_parallel(&unsafe_flows, scope, shared)
-}
-
-fn assign_block_sizes_and_store_overflow(
- unsafe_flow: UnsafeFlow,
- context: &LayoutContext) {
- let assign_block_sizes_traversal = AssignBSizes {
- layout_context: context,
- };
- assign_block_sizes_traversal.run_parallel(unsafe_flow)
-}
-
pub fn traverse_flow_tree_preorder(
root: &mut Flow,
profiler_metadata: Option<TimerMetadata>,
time_profiler_chan: time::ProfilerChan,
- shared: &SharedLayoutContext,
+ context: &LayoutContext,
queue: &rayon::ThreadPool) {
if opts::get().bubble_inline_sizes_separately {
- let context = LayoutContext::new(shared);
let bubble_inline_sizes = BubbleISizes { layout_context: &context };
root.traverse_postorder(&bubble_inline_sizes);
}
+ let assign_isize_traversal = &AssignISizes { layout_context: &context };
+ let assign_bsize_traversal = &AssignBSizes { layout_context: &context };
let nodes = vec![borrowed_flow_to_unsafe_flow(root)].into_boxed_slice();
queue.install(move || {
rayon::scope(move |scope| {
profile(time::ProfilerCategory::LayoutParallelWarmup,
profiler_metadata, time_profiler_chan, move || {
- assign_inline_sizes(nodes, scope, &shared);
+ top_down_flow(&nodes, scope, assign_isize_traversal, assign_bsize_traversal);
});
});
});