diff --git a/components/style/driver.rs b/components/style/driver.rs index 8040757d7c4..6e214f8a50f 100644 --- a/components/style/driver.rs +++ b/components/style/driver.rs @@ -25,11 +25,13 @@ use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken}; /// processing, until we arrive at a wide enough level in the DOM that the /// parallel traversal would parallelize it. If a thread pool is provided, we /// then transfer control over to the parallel traversal. +/// +/// Returns true if the traversal was parallel pub fn traverse_dom( traversal: &D, token: PreTraverseToken, pool: Option<&rayon::ThreadPool> -) +) -> bool where E: TElement, D: DomTraversal, @@ -38,6 +40,7 @@ where token.traversal_root().expect("Should've ensured we needed to traverse"); let dump_stats = traversal.shared_context().options.dump_style_statistics; + let mut used_parallel = false; let start_time = if dump_stats { Some(time::precise_time_s()) } else { None }; // Declare the main-thread context, as well as the worker-thread contexts, @@ -84,6 +87,7 @@ where // moving to the next level in the dom so that we can pass the same // depth for all the children. if pool.is_some() && discovered.len() > WORK_UNIT_MAX { + used_parallel = true; let pool = pool.unwrap(); maybe_tls = Some(ScopedTLS::>::new(pool)); let root_opaque = root.as_node().opaque(); @@ -128,4 +132,6 @@ where println!("{}", aggregate); } } + + used_parallel } diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 53740eb8974..481c555ba1d 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -16,6 +16,7 @@ use media_queries::{Device, MediaList}; use properties::ComputedValues; use servo_arc::Arc; use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; +use std::sync::atomic::{AtomicUsize, Ordering}; use stylesheets::{StylesheetContents, StylesheetInDocument}; use stylist::Stylist; @@ -112,6 +113,10 @@ impl StylesheetInDocument for GeckoStyleSheet { pub struct PerDocumentStyleDataImpl { /// Rule processor. pub stylist: Stylist, + /// Total number of traversals that could have been parallel, for telemetry + pub total_traversal_count: AtomicUsize, + /// Number of parallel traversals + pub parallel_traversal_count: AtomicUsize, } /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics @@ -133,6 +138,8 @@ impl PerDocumentStyleData { PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl { stylist: Stylist::new(device, quirks_mode.into()), + total_traversal_count: Default::default(), + parallel_traversal_count: Default::default(), })) } @@ -147,6 +154,14 @@ impl PerDocumentStyleData { } } +impl Drop for PerDocumentStyleDataImpl { + fn drop(&mut self) { + let total = self.total_traversal_count.load(Ordering::Relaxed) as u32; + let parallel = self.parallel_traversal_count.load(Ordering::Relaxed) as u32; + unsafe { bindings::Gecko_RecordTraversalStatistics(total, parallel) } + } +} + impl PerDocumentStyleDataImpl { /// Recreate the style data if the stylesheets have changed. pub fn flush_stylesheets( @@ -209,6 +224,14 @@ impl PerDocumentStyleDataImpl { pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { self.stylist.add_size_of(ops, sizes); } + + /// Record that a traversal happened for later collection as telemetry + pub fn record_traversal(&self, was_parallel: bool) { + self.total_traversal_count.fetch_add(1, Ordering::Relaxed); + if was_parallel { + self.parallel_traversal_count.fetch_add(1, Ordering::Relaxed); + } + } } unsafe impl HasFFI for PerDocumentStyleData { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index fdd491985f1..bed1bc48dbf 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -267,8 +267,19 @@ fn traverse_subtree( None }; + let is_restyle = element.get_data().is_some(); + let traversal = RecalcStyleOnly::new(shared_style_context); - driver::traverse_dom(&traversal, token, thread_pool); + let used_parallel = driver::traverse_dom(&traversal, token, thread_pool); + + if traversal_flags.contains(TraversalFlags::ParallelTraversal) && + !traversal_flags.contains(TraversalFlags::AnimationOnly) && + is_restyle && !element.is_native_anonymous() { + // We turn off parallel traversal for background tabs; this + // shouldn't count in telemetry. We're also focusing on restyles so + // we ensure that it's a restyle. + per_doc_data.record_traversal(used_parallel); + } } /// Traverses the subtree rooted at `root` for restyling.