Skip to content

Commit

Permalink
Auto merge of #14642 - bholley:scoped_tls, r=emilio
Browse files Browse the repository at this point in the history
Use Scoped TLS in the style system and eliminate UnsafeNode usage in the StyleSharingCandidateCache

See the discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1323372

@emilio Please review, but don't merge yet until we get the upstream changes into Rayon.

CC @SimonSapin @heycam @upsuper @Manishearth @pcwalton @nikomatsakis

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14642)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Dec 21, 2016
2 parents fb45772 + 946e7fb commit 8fd8d61
Show file tree
Hide file tree
Showing 23 changed files with 290 additions and 275 deletions.
20 changes: 16 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion components/layout/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ parking_lot = "0.3.3"
plugins = {path = "../plugins"}
profile_traits = {path = "../profile_traits"}
range = {path = "../range"}
rayon = "0.5"
rayon = "0.6"
script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
selectors = "0.15"
Expand Down
74 changes: 36 additions & 38 deletions components/layout/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,67 +19,72 @@ use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
use parking_lot::RwLock;
use servo_config::opts;
use servo_url::ServoUrl;
use std::borrow::Borrow;
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use style::context::{SharedStyleContext, ThreadLocalStyleContext};
use style::dom::TElement;

pub struct ThreadLocalLayoutContext {
pub style_context: ThreadLocalStyleContext,
/// TLS data scoped to the traversal.
pub struct ScopedThreadLocalLayoutContext<E: TElement> {
pub style_context: ThreadLocalStyleContext<E>,
}

impl<E: TElement> ScopedThreadLocalLayoutContext<E> {
pub fn new(shared: &SharedLayoutContext) -> Self {
ScopedThreadLocalLayoutContext {
style_context: ThreadLocalStyleContext::new(&shared.style_context),
}
}
}

/// TLS data that persists across traversals.
pub struct PersistentThreadLocalLayoutContext {
// FontContext uses Rc all over the place and so isn't Send, which means we
// can't use ScopedTLS for it. There's also no reason to scope it to the
// traversal, and performance is probably better if we don't.
pub font_context: RefCell<FontContext>,
}

impl ThreadLocalLayoutContext {
impl PersistentThreadLocalLayoutContext {
pub fn new(shared: &SharedLayoutContext) -> Rc<Self> {
let font_cache_thread = shared.font_cache_thread.lock().unwrap().clone();
let local_style_data = shared.style_context.local_context_creation_data.lock().unwrap();

Rc::new(ThreadLocalLayoutContext {
style_context: ThreadLocalStyleContext::new(&local_style_data),
Rc::new(PersistentThreadLocalLayoutContext {
font_context: RefCell::new(FontContext::new(font_cache_thread)),
})
}
}

impl Borrow<ThreadLocalStyleContext> for ThreadLocalLayoutContext {
fn borrow(&self) -> &ThreadLocalStyleContext {
&self.style_context
}
}

impl HeapSizeOf for ThreadLocalLayoutContext {
// FIXME(njn): measure other fields eventually.
impl HeapSizeOf for PersistentThreadLocalLayoutContext {
fn heap_size_of_children(&self) -> usize {
self.font_context.heap_size_of_children()
}
}

thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<ThreadLocalLayoutContext>>> = RefCell::new(None));
thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<PersistentThreadLocalLayoutContext>>> = RefCell::new(None));

pub fn heap_size_of_local_context() -> usize {
LOCAL_CONTEXT_KEY.with(|r| {
r.borrow().clone().map_or(0, |context| context.heap_size_of_children())
})
}

// Keep this implementation in sync with the one in ports/geckolib/traversal.rs.
pub fn create_or_get_local_context(shared: &SharedLayoutContext)
-> Rc<ThreadLocalLayoutContext> {
fn create_or_get_persistent_context(shared: &SharedLayoutContext)
-> Rc<PersistentThreadLocalLayoutContext> {
LOCAL_CONTEXT_KEY.with(|r| {
let mut r = r.borrow_mut();
if let Some(context) = r.clone() {
context
} else {
let context = ThreadLocalLayoutContext::new(shared);
let context = PersistentThreadLocalLayoutContext::new(shared);
*r = Some(context.clone());
context
}
})
}

pub fn heap_size_of_persistent_local_context() -> usize {
LOCAL_CONTEXT_KEY.with(|r| {
r.borrow().clone().map_or(0, |context| context.heap_size_of_children())
})
}

/// Layout information shared among all workers. This must be thread-safe.
pub struct SharedLayoutContext {
/// Bits shared by the layout and style system.
Expand All @@ -100,24 +105,17 @@ pub struct SharedLayoutContext {
BuildHasherDefault<FnvHasher>>>>,
}

impl Borrow<SharedStyleContext> for SharedLayoutContext {
fn borrow(&self) -> &SharedStyleContext {
&self.style_context
}
}

pub struct LayoutContext<'a> {
pub shared: &'a SharedLayoutContext,
pub thread_local: &'a ThreadLocalLayoutContext,
pub persistent: Rc<PersistentThreadLocalLayoutContext>,
}

impl<'a> LayoutContext<'a> {
pub fn new(shared: &'a SharedLayoutContext,
thread_local: &'a ThreadLocalLayoutContext) -> Self
pub fn new(shared: &'a SharedLayoutContext) -> Self
{
LayoutContext {
shared: shared,
thread_local: thread_local,
persistent: create_or_get_persistent_context(shared),
}
}
}
Expand All @@ -138,7 +136,7 @@ impl<'a> LayoutContext<'a> {

#[inline(always)]
pub fn font_context(&self) -> RefMut<FontContext> {
self.thread_local.font_context.borrow_mut()
self.persistent.font_context.borrow_mut()
}
}

Expand Down
37 changes: 17 additions & 20 deletions components/layout/parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

#![allow(unsafe_code)]

use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext};
use context::create_or_get_local_context;
use context::{LayoutContext, SharedLayoutContext};
use flow::{self, Flow, MutableFlowUtils, PostorderFlowTraversal, PreorderFlowTraversal};
use flow_ref::FlowRef;
use profile_traits::time::{self, TimerMetadata, profile};
Expand Down Expand Up @@ -51,7 +50,7 @@ pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow {
}

pub type ChunkedFlowTraversalFunction<'scope> =
extern "Rust" fn(Box<[UnsafeFlow]>, &'scope SharedLayoutContext, &rayon::Scope<'scope>);
extern "Rust" fn(Box<[UnsafeFlow]>, &rayon::Scope<'scope>, &'scope SharedLayoutContext);

pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &LayoutContext);

Expand Down Expand Up @@ -133,23 +132,22 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
fn run_parallel<'scope>(&self,
unsafe_flows: &[UnsafeFlow],
layout_context: &'scope SharedLayoutContext,
scope: &rayon::Scope<'scope>);
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],
shared: &'scope SharedLayoutContext,
scope: &rayon::Scope<'scope>,
shared: &'scope SharedLayoutContext,
top_down_func: ChunkedFlowTraversalFunction<'scope>,
bottom_up_func: FlowTraversalFunction)
{
let tlc = create_or_get_local_context(shared);
let context = LayoutContext::new(&shared, &*tlc);

let mut discovered_child_flows = vec![];
let context = LayoutContext::new(&shared);

for unsafe_flow in unsafe_flows {
let mut had_children = false;
unsafe {
Expand Down Expand Up @@ -187,7 +185,7 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();

scope.spawn(move |scope| {
top_down_func(nodes, shared, scope);
top_down_func(nodes, scope, shared);
});
}
}
Expand All @@ -196,12 +194,12 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> {
fn run_parallel<'scope>(&self,
unsafe_flows: &[UnsafeFlow],
layout_context: &'scope SharedLayoutContext,
scope: &rayon::Scope<'scope>)
scope: &rayon::Scope<'scope>,
shared: &'scope SharedLayoutContext)
{
self.run_parallel_helper(unsafe_flows,
layout_context,
scope,
shared,
assign_inline_sizes,
assign_block_sizes_and_store_overflow)
}
Expand All @@ -214,12 +212,12 @@ impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> {
impl<'a> ParallelPostorderFlowTraversal for AssignBSizes<'a> {}

fn assign_inline_sizes<'scope>(unsafe_flows: Box<[UnsafeFlow]>,
shared_layout_context: &'scope SharedLayoutContext,
scope: &rayon::Scope<'scope>) {
scope: &rayon::Scope<'scope>,
shared: &'scope SharedLayoutContext) {
let assign_inline_sizes_traversal = AssignISizes {
shared_context: &shared_layout_context.style_context,
shared_context: &shared.style_context,
};
assign_inline_sizes_traversal.run_parallel(&unsafe_flows, shared_layout_context, scope)
assign_inline_sizes_traversal.run_parallel(&unsafe_flows, scope, shared)
}

fn assign_block_sizes_and_store_overflow(
Expand All @@ -238,8 +236,7 @@ pub fn traverse_flow_tree_preorder(
shared: &SharedLayoutContext,
queue: &rayon::ThreadPool) {
if opts::get().bubble_inline_sizes_separately {
let tlc = ThreadLocalLayoutContext::new(shared);
let context = LayoutContext::new(shared, &*tlc);
let context = LayoutContext::new(shared);
let bubble_inline_sizes = BubbleISizes { layout_context: &context };
root.traverse_postorder(&bubble_inline_sizes);
}
Expand All @@ -250,7 +247,7 @@ pub fn traverse_flow_tree_preorder(
rayon::scope(move |scope| {
profile(time::ProfilerCategory::LayoutParallelWarmup,
profiler_metadata, time_profiler_chan, move || {
assign_inline_sizes(nodes, &shared, scope);
assign_inline_sizes(nodes, scope, &shared);
});
});
});
Expand Down
7 changes: 3 additions & 4 deletions components/layout/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@

use app_units::Au;
use construct::ConstructionResult;
use context::SharedLayoutContext;
use context::create_or_get_local_context;
use context::{ScopedThreadLocalLayoutContext, SharedLayoutContext};
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
Expand Down Expand Up @@ -646,10 +645,10 @@ pub fn process_resolved_style_request<'a, N>(shared: &SharedLayoutContext,
// we'd need a mechanism to prevent detect when it's stale (since we don't
// traverse display:none subtrees during restyle).
let display_none_root = if element.get_data().is_none() {
let tlc = create_or_get_local_context(shared);
let mut tlc = ScopedThreadLocalLayoutContext::new(shared);
let context = StyleContext {
shared: &shared.style_context,
thread_local: &tlc.style_context,
thread_local: &mut tlc.style_context,
};

Some(style_element_in_display_none_subtree(&context, element,
Expand Down
8 changes: 3 additions & 5 deletions components/layout/sequential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! Implements sequential traversals over the DOM and flow trees.

use app_units::Au;
use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext};
use context::{LayoutContext, SharedLayoutContext};
use display_list_builder::DisplayListBuildState;
use euclid::point::Point2D;
use floats::SpeculatedFloatPlacement;
Expand Down Expand Up @@ -34,8 +34,7 @@ pub fn resolve_generated_content(root: &mut Flow, shared: &SharedLayoutContext)
}
}

let tlc = ThreadLocalLayoutContext::new(shared);
let layout_context = LayoutContext::new(shared, &*tlc);
let layout_context = LayoutContext::new(shared);
let mut traversal = ResolveGeneratedContent::new(&layout_context);
doit(root, 0, &mut traversal)
}
Expand All @@ -58,8 +57,7 @@ pub fn traverse_flow_tree_preorder(root: &mut Flow,
}
}

let tlc = ThreadLocalLayoutContext::new(shared);
let layout_context = LayoutContext::new(shared, &*tlc);
let layout_context = LayoutContext::new(shared);

if opts::get().bubble_inline_sizes_separately {
let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
Expand Down
Loading

0 comments on commit 8fd8d61

Please sign in to comment.