diff --git a/components/style/context.rs b/components/style/context.rs index e6a7b544ab0..f9e61523e2e 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -296,7 +296,7 @@ impl ElementCascadeInputs { /// thread and then combine them after the threads join via the Add /// implementation below. #[derive(Default)] -pub struct TraversalStatistics { +pub struct PerThreadTraversalStatistics { /// The total number of elements traversed. pub elements_traversed: u32, /// The number of elements where has_styles() went from false to true. @@ -308,6 +308,28 @@ pub struct TraversalStatistics { /// The number of styles reused via rule node comparison from the /// StyleSharingCache. pub styles_reused: u32, +} + +/// Implementation of Add to aggregate statistics across different threads. +impl<'a> ops::Add for &'a PerThreadTraversalStatistics { + type Output = PerThreadTraversalStatistics; + fn add(self, other: Self) -> PerThreadTraversalStatistics { + PerThreadTraversalStatistics { + elements_traversed: self.elements_traversed + other.elements_traversed, + elements_styled: self.elements_styled + other.elements_styled, + elements_matched: self.elements_matched + other.elements_matched, + styles_shared: self.styles_shared + other.styles_shared, + styles_reused: self.styles_reused + other.styles_reused, + } + } +} + +/// Statistics gathered during the traversal plus some information from +/// other sources including stylist. +#[derive(Default)] +pub struct TraversalStatistics { + /// Aggregated statistics gathered during the traversal. + pub aggregated: PerThreadTraversalStatistics, /// The number of selectors in the stylist. pub selectors: u32, /// The number of revalidation selectors. @@ -321,38 +343,9 @@ pub struct TraversalStatistics { /// Time spent in the traversal, in milliseconds. pub traversal_time_ms: f64, /// Whether this was a parallel traversal. - pub is_parallel: Option, + pub is_parallel: bool, /// Whether this is a "large" traversal. - pub is_large: Option, -} - -/// Implementation of Add to aggregate statistics across different threads. -impl<'a> ops::Add for &'a TraversalStatistics { - type Output = TraversalStatistics; - fn add(self, other: Self) -> TraversalStatistics { - debug_assert!(self.traversal_time_ms == 0.0 && other.traversal_time_ms == 0.0, - "traversal_time_ms should be set at the end by the caller"); - debug_assert!(self.selectors == 0, "set at the end"); - debug_assert!(self.revalidation_selectors == 0, "set at the end"); - debug_assert!(self.dependency_selectors == 0, "set at the end"); - debug_assert!(self.declarations == 0, "set at the end"); - debug_assert!(self.stylist_rebuilds == 0, "set at the end"); - TraversalStatistics { - elements_traversed: self.elements_traversed + other.elements_traversed, - elements_styled: self.elements_styled + other.elements_styled, - elements_matched: self.elements_matched + other.elements_matched, - styles_shared: self.styles_shared + other.styles_shared, - styles_reused: self.styles_reused + other.styles_reused, - selectors: 0, - revalidation_selectors: 0, - dependency_selectors: 0, - declarations: 0, - stylist_rebuilds: 0, - traversal_time_ms: 0.0, - is_parallel: None, - is_large: None, - } - } + pub is_large: bool, } /// Format the statistics in a way that the performance test harness understands. @@ -361,16 +354,16 @@ impl fmt::Display for TraversalStatistics { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { debug_assert!(self.traversal_time_ms != 0.0, "should have set traversal time"); writeln!(f, "[PERF] perf block start")?; - writeln!(f, "[PERF],traversal,{}", if self.is_parallel.unwrap() { + writeln!(f, "[PERF],traversal,{}", if self.is_parallel { "parallel" } else { "sequential" })?; - writeln!(f, "[PERF],elements_traversed,{}", self.elements_traversed)?; - writeln!(f, "[PERF],elements_styled,{}", self.elements_styled)?; - writeln!(f, "[PERF],elements_matched,{}", self.elements_matched)?; - writeln!(f, "[PERF],styles_shared,{}", self.styles_shared)?; - writeln!(f, "[PERF],styles_reused,{}", self.styles_reused)?; + writeln!(f, "[PERF],elements_traversed,{}", self.aggregated.elements_traversed)?; + writeln!(f, "[PERF],elements_styled,{}", self.aggregated.elements_styled)?; + writeln!(f, "[PERF],elements_matched,{}", self.aggregated.elements_matched)?; + writeln!(f, "[PERF],styles_shared,{}", self.aggregated.styles_shared)?; + writeln!(f, "[PERF],styles_reused,{}", self.aggregated.styles_reused)?; writeln!(f, "[PERF],selectors,{}", self.selectors)?; writeln!(f, "[PERF],revalidation_selectors,{}", self.revalidation_selectors)?; writeln!(f, "[PERF],dependency_selectors,{}", self.dependency_selectors)?; @@ -382,29 +375,33 @@ impl fmt::Display for TraversalStatistics { } impl TraversalStatistics { - /// Computes the traversal time given the start time in seconds. - pub fn finish(&mut self, traversal: &D, parallel: bool, start: f64) + /// Generate complete traversal statistics. + /// + /// The traversal time is computed given the start time in seconds. + pub fn new( + aggregated: PerThreadTraversalStatistics, + traversal: &D, + parallel: bool, + start: f64 + ) -> TraversalStatistics where E: TElement, D: DomTraversal, { let threshold = traversal.shared_context().options.style_statistics_threshold; let stylist = traversal.shared_context().stylist; - - self.is_parallel = Some(parallel); - self.is_large = Some(self.elements_traversed as usize >= threshold); - self.traversal_time_ms = (time::precise_time_s() - start) * 1000.0; - self.selectors = stylist.num_selectors() as u32; - self.revalidation_selectors = stylist.num_revalidation_selectors() as u32; - self.dependency_selectors = stylist.num_invalidations() as u32; - self.declarations = stylist.num_declarations() as u32; - self.stylist_rebuilds = stylist.num_rebuilds() as u32; - } - - /// Returns whether this traversal is 'large' in order to avoid console spam - /// from lots of tiny traversals. - pub fn is_large_traversal(&self) -> bool { - self.is_large.unwrap() + let is_large = aggregated.elements_traversed as usize >= threshold; + TraversalStatistics { + aggregated, + selectors: stylist.num_selectors() as u32, + revalidation_selectors: stylist.num_revalidation_selectors() as u32, + dependency_selectors: stylist.num_invalidations() as u32, + declarations: stylist.num_declarations() as u32, + stylist_rebuilds: stylist.num_rebuilds() as u32, + traversal_time_ms: (time::precise_time_s() - start) * 1000.0, + is_parallel: parallel, + is_large + } } } @@ -714,7 +711,7 @@ pub struct ThreadLocalStyleContext { /// than the current element). pub selector_flags: SelectorFlagsMap, /// Statistics about the traversal. - pub statistics: TraversalStatistics, + pub statistics: PerThreadTraversalStatistics, /// The struct used to compute and cache font metrics from style /// for evaluation of the font-relative em/ch units and font-size pub font_metrics_provider: E::FontMetricsProvider, @@ -736,7 +733,7 @@ impl ThreadLocalStyleContext { new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(), tasks: SequentialTaskList(Vec::new()), selector_flags: SelectorFlagsMap::new(), - statistics: TraversalStatistics::default(), + statistics: PerThreadTraversalStatistics::default(), font_metrics_provider: E::FontMetricsProvider::create_from(shared), stack_limit_checker: StackLimitChecker::new( (STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024), @@ -753,7 +750,7 @@ impl ThreadLocalStyleContext { bloom_filter: StyleBloom::new(), tasks: SequentialTaskList(Vec::new()), selector_flags: SelectorFlagsMap::new(), - statistics: TraversalStatistics::default(), + statistics: PerThreadTraversalStatistics::default(), font_metrics_provider: E::FontMetricsProvider::create_from(shared), stack_limit_checker: StackLimitChecker::new( (STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024), diff --git a/components/style/driver.rs b/components/style/driver.rs index 93983233c4f..6f99b542a5f 100644 --- a/components/style/driver.rs +++ b/components/style/driver.rs @@ -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}; @@ -128,9 +128,14 @@ where }); } - aggregate.finish(traversal, parallel, start_time.unwrap()); - if aggregate.is_large_traversal() { - println!("{}", aggregate); + let stats = TraversalStatistics::new( + aggregate, + traversal, + parallel, + start_time.unwrap() + ); + if stats.is_large { + println!("{}", stats); } } }