diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/layout/context.rs | 4 | ||||
-rw-r--r-- | components/layout/css/matching.rs | 1 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 8 | ||||
-rw-r--r-- | components/layout/parallel.rs | 33 | ||||
-rw-r--r-- | components/util/lib.rs | 1 | ||||
-rw-r--r-- | components/util/namespace.rs | 2 | ||||
-rw-r--r-- | components/util/tid.rs | 18 |
7 files changed, 59 insertions, 8 deletions
diff --git a/components/layout/context.rs b/components/layout/context.rs index 936314dcb63..8792e99d2a6 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -79,6 +79,10 @@ pub struct SharedLayoutContext { /// The dirty rectangle, used during display list building. pub dirty: Rect<Au>, + + /// Starts at zero, and increased by one every time a layout completes. + /// This can be used to easily check for invalid stale data. + pub generation: uint, } pub struct LayoutContext<'a> { diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs index 7abc683f4ad..4c94692a0f0 100644 --- a/components/layout/css/matching.rs +++ b/components/layout/css/matching.rs @@ -17,6 +17,7 @@ use servo_util::cache::{Cache, LRUCache, SimpleHashCache}; use servo_util::namespace::Null; use servo_util::smallvec::{SmallVec, SmallVec16}; use servo_util::str::DOMString; +use servo_util::tid::tid; use std::mem; use std::hash::{Hash, sip}; use std::slice::Items; diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index fa42cb04f59..d6811617c0a 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -88,6 +88,10 @@ pub struct LayoutTaskData { /// The dirty rect. Used during display list construction. pub dirty: Rect<Au>, + + /// Starts at zero, and increased by one every time a layout completes. + /// This can be used to easily check for invalid stale data. + pub generation: uint, } /// Information needed by the layout task. @@ -413,6 +417,7 @@ impl LayoutTask { stylist: box Stylist::new(), parallel_traversal: parallel_traversal, dirty: Rect::zero(), + generation: 0, })), } } @@ -443,6 +448,7 @@ impl LayoutTask { reflow_root: OpaqueNodeMethods::from_layout_node(reflow_root), opts: self.opts.clone(), dirty: Rect::zero(), + generation: rw_data.generation, } } @@ -925,6 +931,8 @@ impl LayoutTask { layout_debug::end_trace(); } + rw_data.generation += 1; + // Tell script that we're done. // // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index f24b4b10e0c..30d431b389f 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -22,6 +22,7 @@ use wrapper::{ThreadSafeLayoutNode, UnsafeLayoutNode}; use gfx::display_list::OpaqueNode; use servo_util::bloom::BloomFilter; +use servo_util::tid::tid; use servo_util::time::{TimeProfilerChan, profile}; use servo_util::time; use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy}; @@ -216,6 +217,10 @@ impl<'a> ParallelPreorderFlowTraversal for AssignISizesTraversal<'a> { impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversal<'a> {} +/// Every time we do another layout, the old bloom filters are invalid. This is +/// detected by ticking a generation number every layout. +type Generation = uint; + /// A pair of the bloom filter used for css selector matching, and the node to /// which it applies. This is used to efficiently do `Descendant` selector /// matches. Thanks to the bloom filter, we can avoid walking up the tree @@ -236,7 +241,7 @@ impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversa /// Since a work-stealing queue is used for styling, sometimes, the bloom filter /// will no longer be the for the parent of the node we're currently on. When /// this happens, the task local bloom filter will be thrown away and rebuilt. -local_data_key!(style_bloom: (BloomFilter, UnsafeLayoutNode)) +local_data_key!(style_bloom: (BloomFilter, UnsafeLayoutNode, Generation)) /// Returns the task local bloom filter. /// @@ -251,6 +256,9 @@ fn take_task_local_bloom_filter( |p: Option<LayoutNode>| -> BloomFilter { let mut bf = BloomFilter::new(style::RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE); p.map(|p| insert_ancestors_into_bloom_filter(&mut bf, p, layout_context)); + if p.is_none() { + debug!("[{}] No parent, but new bloom filter!", tid()); + } bf }; @@ -260,9 +268,11 @@ fn take_task_local_bloom_filter( // No bloom filter for this thread yet. (Some(p), None) => new_bloom(Some(p)), // Found cached bloom filter. - (Some(p), Some((bf, old_node))) => { + (Some(p), Some((bf, old_node, old_generation))) => { // Hey, the cached parent is our parent! We can reuse the bloom filter. - if old_node == layout_node_to_unsafe_layout_node(&p) { + if old_node == layout_node_to_unsafe_layout_node(&p) && + old_generation == layout_context.shared.generation { + debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.val0()); bf // Oh no. the cached parent is stale. I guess we need a new one... } else { @@ -272,8 +282,8 @@ fn take_task_local_bloom_filter( } } -fn put_task_local_bloom_filter(bf: BloomFilter, unsafe_node: &UnsafeLayoutNode) { - match style_bloom.replace(Some((bf, *unsafe_node))) { +fn put_task_local_bloom_filter(bf: BloomFilter, unsafe_node: &UnsafeLayoutNode, layout_context: &LayoutContext) { + match style_bloom.replace(Some((bf, *unsafe_node, layout_context.shared.generation))) { None => {}, Some(_) => fail!("Putting into a never-taken task-local bloom filter"), } @@ -282,13 +292,18 @@ fn put_task_local_bloom_filter(bf: BloomFilter, unsafe_node: &UnsafeLayoutNode) /// "Ancestors" in this context is inclusive of ourselves. fn insert_ancestors_into_bloom_filter( bf: &mut BloomFilter, mut n: LayoutNode, layout_context: &LayoutContext) { + debug!("[{}] Inserting ancestors.", tid()); + let mut ancestors = 0u; loop { + ancestors += 1; + n.insert_into_bloom_filter(bf); n = match parent_node(&n, layout_context) { - None => return, + None => break, Some(p) => p, }; } + debug!("[{}] Inserted {} ancestors.", tid(), ancestors); } fn parent_node<'ln>(node: &LayoutNode<'ln>, layout_context: &LayoutContext) -> Option<LayoutNode<'ln>> { @@ -378,6 +393,7 @@ fn recalc_style_for_node(mut unsafe_layout_node: UnsafeLayoutNode, // Before running the children, we need to insert our nodes into the bloom // filter. + debug!("[{}] + {:X}", tid(), unsafe_layout_node.val0()); bf.as_mut().map(|bf| node.insert_into_bloom_filter(bf)); // It's *very* important that this block is in a separate scope to the block above, @@ -399,7 +415,7 @@ fn recalc_style_for_node(mut unsafe_layout_node: UnsafeLayoutNode, construct_flows(&mut unsafe_layout_node, &mut bf, &layout_context); } - bf.map(|bf| put_task_local_bloom_filter(bf, &unsafe_layout_node)); + bf.map(|bf| put_task_local_bloom_filter(bf, &unsafe_layout_node, &layout_context)); } fn construct_flows<'a>(unsafe_layout_node: &mut UnsafeLayoutNode, @@ -437,9 +453,11 @@ fn construct_flows<'a>(unsafe_layout_node: &mut UnsafeLayoutNode, // If this is the reflow root, we're done. let opaque_node: OpaqueNode = OpaqueNodeMethods::from_layout_node(&node); if layout_context.shared.reflow_root == opaque_node { + debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.val0()); *parent_bf = None; break; } else { + debug!("[{}] - {:X}", tid(), unsafe_layout_node.val0()); parent_bf.as_mut().map(|parent_bf| node.remove_from_bloom_filter(parent_bf)); } @@ -611,6 +629,7 @@ fn build_display_list(mut unsafe_flow: UnsafeFlow, pub fn recalc_style_for_subtree(root_node: &LayoutNode, shared_layout_context: &SharedLayoutContext, queue: &mut WorkQueue<*const SharedLayoutContext,UnsafeLayoutNode>) { + debug!("[{}] Style Recalc START", tid()); queue.data = shared_layout_context as *const _; // Enqueue the root node. diff --git a/components/util/lib.rs b/components/util/lib.rs index 9e6bddb9fab..a62c35ee576 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -44,6 +44,7 @@ pub mod smallvec; pub mod sort; pub mod str; pub mod task; +pub mod tid; pub mod time; pub mod vec; pub mod workqueue; diff --git a/components/util/namespace.rs b/components/util/namespace.rs index 8824accae00..b33012a9ef1 100644 --- a/components/util/namespace.rs +++ b/components/util/namespace.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#[deriving(Eq, PartialEq, Clone, Encodable, Hash)] +#[deriving(Eq, PartialEq, Clone, Encodable, Hash, Show)] pub enum Namespace { Null, HTML, diff --git a/components/util/tid.rs b/components/util/tid.rs new file mode 100644 index 00000000000..fdd9a775bcd --- /dev/null +++ b/components/util/tid.rs @@ -0,0 +1,18 @@ +use std::sync::atomics::{AtomicUint, INIT_ATOMIC_UINT, SeqCst}; + +static mut next_tid: AtomicUint = INIT_ATOMIC_UINT; + +local_data_key!(task_local_tid: uint) + +/// Every task gets one, that's unique. +pub fn tid() -> uint { + let ret = + match task_local_tid.replace(None) { + None => unsafe { next_tid.fetch_add(1, SeqCst) }, + Some(x) => x, + }; + + task_local_tid.replace(Some(ret)); + + ret +} |