mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Add weighted telemetry probes for parallel restyles
This commit is contained in:
parent
d573081fe5
commit
337e5288c2
6 changed files with 84 additions and 26 deletions
|
@ -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.
|
/// A shared style context.
|
||||||
///
|
///
|
||||||
/// There's exactly one of these during a given restyle traversal, and it's
|
/// There's exactly one of these during a given restyle traversal, and it's
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use context::{StyleContext, ThreadLocalStyleContext};
|
use context::{StyleContext, ThreadLocalStyleContext, TraversalStatistics};
|
||||||
use dom::{SendNode, TElement, TNode};
|
use dom::{SendNode, TElement, TNode};
|
||||||
use parallel;
|
use parallel;
|
||||||
use parallel::{DispatchMode, WORK_UNIT_MAX};
|
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
|
/// parallel traversal would parallelize it. If a thread pool is provided, we
|
||||||
/// then transfer control over to the parallel traversal.
|
/// 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>(
|
pub fn traverse_dom<E, D>(
|
||||||
traversal: &D,
|
traversal: &D,
|
||||||
token: PreTraverseToken<E>,
|
token: PreTraverseToken<E>,
|
||||||
pool: Option<&rayon::ThreadPool>
|
pool: Option<&rayon::ThreadPool>
|
||||||
) -> bool
|
) -> (bool, Option<TraversalStatistics>)
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
D: DomTraversal<E>,
|
D: DomTraversal<E>,
|
||||||
|
@ -40,6 +42,7 @@ where
|
||||||
token.traversal_root().expect("Should've ensured we needed to traverse");
|
token.traversal_root().expect("Should've ensured we needed to traverse");
|
||||||
|
|
||||||
let dump_stats = traversal.shared_context().options.dump_style_statistics;
|
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 mut used_parallel = false;
|
||||||
let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };
|
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();
|
nodes_remaining_at_current_depth = discovered.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut maybe_stats = None;
|
||||||
// Dump statistics to stdout if requested.
|
// Accumulate statistics
|
||||||
if dump_stats {
|
if dump_stats || is_nightly {
|
||||||
let mut aggregate =
|
let mut aggregate =
|
||||||
mem::replace(&mut context.thread_local.statistics, Default::default());
|
mem::replace(&mut context.thread_local.statistics, Default::default());
|
||||||
let parallel = maybe_tls.is_some();
|
let parallel = maybe_tls.is_some();
|
||||||
|
@ -127,11 +130,14 @@ where
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
aggregate.finish(traversal, parallel, start_time.unwrap());
|
|
||||||
if aggregate.is_large_traversal() {
|
// dump to stdout if requested
|
||||||
println!("{}", aggregate);
|
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.
|
//! Data needed to style a Gecko document.
|
||||||
|
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||||
|
use context::TraversalStatistics;
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use gecko_bindings::bindings::{self, RawServoStyleSet};
|
use gecko_bindings::bindings::{self, RawServoStyleSet};
|
||||||
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
|
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
|
/// The container for data that a Servo-backed Gecko document needs to style
|
||||||
/// itself.
|
/// itself.
|
||||||
pub struct PerDocumentStyleDataImpl {
|
pub struct PerDocumentStyleDataImpl {
|
||||||
/// Rule processor.
|
/// Rule processor.
|
||||||
pub stylist: Stylist,
|
pub stylist: Stylist,
|
||||||
/// Total number of traversals that could have been parallel, for telemetry
|
/// Counter for traversals that could have been parallel, for telemetry
|
||||||
pub total_traversal_count: AtomicUsize,
|
pub traversal_count: TraversalCount,
|
||||||
/// Number of parallel traversals
|
/// Counter for traversals, weighted by elements traversed,
|
||||||
pub parallel_traversal_count: AtomicUsize,
|
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
|
/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
|
||||||
|
@ -138,8 +164,9 @@ impl PerDocumentStyleData {
|
||||||
|
|
||||||
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
|
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
|
||||||
stylist: Stylist::new(device, quirks_mode.into()),
|
stylist: Stylist::new(device, quirks_mode.into()),
|
||||||
total_traversal_count: Default::default(),
|
traversal_count: Default::default(),
|
||||||
parallel_traversal_count: Default::default(),
|
traversal_count_traversed: Default::default(),
|
||||||
|
traversal_count_styled: Default::default(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,9 +183,16 @@ impl PerDocumentStyleData {
|
||||||
|
|
||||||
impl Drop for PerDocumentStyleDataImpl {
|
impl Drop for PerDocumentStyleDataImpl {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let total = self.total_traversal_count.load(Ordering::Relaxed) as u32;
|
if !structs::GECKO_IS_NIGHTLY {
|
||||||
let parallel = self.parallel_traversal_count.load(Ordering::Relaxed) as u32;
|
return
|
||||||
unsafe { bindings::Gecko_RecordTraversalStatistics(total, parallel) }
|
}
|
||||||
|
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
|
/// Record that a traversal happened for later collection as telemetry
|
||||||
pub fn record_traversal(&self, was_parallel: bool) {
|
pub fn record_traversal(&self, was_parallel: bool, stats: Option<TraversalStatistics>) {
|
||||||
self.total_traversal_count.fetch_add(1, Ordering::Relaxed);
|
self.traversal_count.record(was_parallel, 1);
|
||||||
if was_parallel {
|
if let Some(stats) = stats {
|
||||||
self.parallel_traversal_count.fetch_add(1, Ordering::Relaxed);
|
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 , ) ;
|
pub fn Servo_SelectorList_Drop ( ptr : RawServoSelectorListOwned , ) ;
|
||||||
} extern "C" {
|
} extern "C" {
|
||||||
pub fn Servo_SourceSizeList_Drop ( ptr : RawServoSourceSizeListOwned , ) ;
|
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" {
|
} extern "C" {
|
||||||
pub fn Gecko_IsInDocument ( node : RawGeckoNodeBorrowed , ) -> bool ;
|
pub fn Gecko_IsInDocument ( node : RawGeckoNodeBorrowed , ) -> bool ;
|
||||||
} extern "C" {
|
} extern "C" {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -270,7 +270,7 @@ fn traverse_subtree(
|
||||||
let is_restyle = element.get_data().is_some();
|
let is_restyle = element.get_data().is_some();
|
||||||
|
|
||||||
let traversal = RecalcStyleOnly::new(shared_style_context);
|
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) &&
|
if traversal_flags.contains(TraversalFlags::ParallelTraversal) &&
|
||||||
!traversal_flags.contains(TraversalFlags::AnimationOnly) &&
|
!traversal_flags.contains(TraversalFlags::AnimationOnly) &&
|
||||||
|
@ -278,7 +278,7 @@ fn traverse_subtree(
|
||||||
// We turn off parallel traversal for background tabs; this
|
// We turn off parallel traversal for background tabs; this
|
||||||
// shouldn't count in telemetry. We're also focusing on restyles so
|
// shouldn't count in telemetry. We're also focusing on restyles so
|
||||||
// we ensure that it's a restyle.
|
// we ensure that it's a restyle.
|
||||||
per_doc_data.record_traversal(used_parallel);
|
per_doc_data.record_traversal(used_parallel, stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue