Skip to content
Permalink
Browse files

Add weighted telemetry probes for parallel restyles

  • Loading branch information
Manishearth committed Dec 12, 2017
1 parent d573081 commit 337e5288c20e94bfaebae8ea32eb13704fdc6b87
@@ -116,6 +116,21 @@ impl Default for StyleSystemOptions {
}
}

impl StyleSystemOptions {
#[cfg(feature = "servo")]
/// On Gecko's nightly build?
pub fn is_nightly(&self) -> bool {
false
}

#[cfg(feature = "gecko")]
/// On Gecko's nightly build?
#[inline]
pub fn is_nightly(&self) -> bool {
structs::GECKO_IS_NIGHTLY
}
}

/// A shared style context.
///
/// There's exactly one of these during a given restyle traversal, and it's
@@ -7,7 +7,7 @@

#![deny(missing_docs)]

use context::{StyleContext, ThreadLocalStyleContext};
use context::{StyleContext, ThreadLocalStyleContext, TraversalStatistics};
use dom::{SendNode, TElement, TNode};
use parallel;
use parallel::{DispatchMode, WORK_UNIT_MAX};
@@ -26,12 +26,14 @@ use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
/// 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
/// Returns true if the traversal was parallel, and also returns the statistics
/// object containing information on nodes traversed (on nightly only). Not
/// all of its fields will be initialized since we don't call finish().
pub fn traverse_dom<E, D>(
traversal: &D,
token: PreTraverseToken<E>,
pool: Option<&rayon::ThreadPool>
) -> bool
) -> (bool, Option<TraversalStatistics>)
where
E: TElement,
D: DomTraversal<E>,
@@ -40,6 +42,7 @@ where
token.traversal_root().expect("Should've ensured we needed to traverse");

let dump_stats = traversal.shared_context().options.dump_style_statistics;
let is_nightly = traversal.shared_context().options.is_nightly();
let mut used_parallel = false;
let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

@@ -112,9 +115,9 @@ where
nodes_remaining_at_current_depth = discovered.len();
}
}

// Dump statistics to stdout if requested.
if dump_stats {
let mut maybe_stats = None;
// Accumulate statistics
if dump_stats || is_nightly {
let mut aggregate =
mem::replace(&mut context.thread_local.statistics, Default::default());
let parallel = maybe_tls.is_some();
@@ -127,11 +130,14 @@ where
}
});
}
aggregate.finish(traversal, parallel, start_time.unwrap());
if aggregate.is_large_traversal() {
println!("{}", aggregate);

// dump to stdout if requested
if dump_stats && aggregate.is_large_traversal() {
aggregate.finish(traversal, parallel, start_time.unwrap());
println!("{}", aggregate);
}
maybe_stats = Some(aggregate);
}

used_parallel
(used_parallel, maybe_stats)
}
@@ -5,6 +5,7 @@
//! Data needed to style a Gecko document.

use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use context::TraversalStatistics;
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
@@ -108,15 +109,40 @@ impl StylesheetInDocument for GeckoStyleSheet {
}
}

#[derive(Default)]
/// Helper struct for counting traversals
pub struct TraversalCount {
/// Total number of events
pub total_count: AtomicUsize,
/// Number of events which were parallel
pub parallel_count: AtomicUsize
}

impl TraversalCount {
fn record(&self, parallel: bool, count: u32) {
self.total_count.fetch_add(count as usize, Ordering::Relaxed);
if parallel {
self.parallel_count.fetch_add(count as usize, Ordering::Relaxed);
}
}

fn get(&self) -> (u32, u32) {
(self.total_count.load(Ordering::Relaxed) as u32,
self.parallel_count.load(Ordering::Relaxed) as u32)
}
}

/// The container for data that a Servo-backed Gecko document needs to style
/// itself.
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,
/// Counter for traversals that could have been parallel, for telemetry
pub traversal_count: TraversalCount,
/// Counter for traversals, weighted by elements traversed,
pub traversal_count_traversed: TraversalCount,
/// Counter for traversals, weighted by elements styled,
pub traversal_count_styled: TraversalCount,
}

/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
@@ -138,8 +164,9 @@ impl PerDocumentStyleData {

PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
stylist: Stylist::new(device, quirks_mode.into()),
total_traversal_count: Default::default(),
parallel_traversal_count: Default::default(),
traversal_count: Default::default(),
traversal_count_traversed: Default::default(),
traversal_count_styled: Default::default(),
}))
}

@@ -156,9 +183,16 @@ 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) }
if !structs::GECKO_IS_NIGHTLY {
return
}
let (total, parallel) = self.traversal_count.get();
let (total_t, parallel_t) = self.traversal_count_traversed.get();
let (total_s, parallel_s) = self.traversal_count_styled.get();

unsafe { bindings::Gecko_RecordTraversalStatistics(total, parallel,
total_t, parallel_t,
total_s, parallel_s) }
}
}

@@ -226,10 +260,11 @@ impl PerDocumentStyleDataImpl {
}

/// 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);
pub fn record_traversal(&self, was_parallel: bool, stats: Option<TraversalStatistics>) {
self.traversal_count.record(was_parallel, 1);
if let Some(stats) = stats {
self.traversal_count_traversed.record(was_parallel, stats.elements_traversed);
self.traversal_count_styled.record(was_parallel, stats.elements_styled);
}
}
}
@@ -499,6 +499,8 @@ extern "C" {
pub fn Servo_SelectorList_Drop ( ptr : RawServoSelectorListOwned , ) ;
} extern "C" {
pub fn Servo_SourceSizeList_Drop ( ptr : RawServoSourceSizeListOwned , ) ;
} extern "C" {
pub fn Gecko_RecordTraversalStatistics ( total : u32 , parallel : u32 , total_t : u32 , parallel_t : u32 , total_s : u32 , parallel_s : u32 , ) ;
} extern "C" {
pub fn Gecko_IsInDocument ( node : RawGeckoNodeBorrowed , ) -> bool ;
} extern "C" {

Large diffs are not rendered by default.

@@ -270,15 +270,15 @@ fn traverse_subtree(
let is_restyle = element.get_data().is_some();

let traversal = RecalcStyleOnly::new(shared_style_context);
let used_parallel = driver::traverse_dom(&traversal, token, thread_pool);
let (used_parallel, stats) = 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);
per_doc_data.record_traversal(used_parallel, stats);
}
}

0 comments on commit 337e528

Please sign in to comment.
You can’t perform that action at this time.