From f7023a120e72abc7013c76147577dfad2b4b3c73 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 20 Sep 2017 08:50:21 +1000 Subject: [PATCH] Measure the UA cache. ServoStyleSetSizes now has two uses, one for the Stylist, and one for the UA cache, and so the patch removes 'Stylist' from the field names. Example output from about:memory: > +----1,359,608 B (00.55%) -- layout > | +----756,488 B (00.31%) -- style-sheet-cache [2] > | +----393,968 B (00.16%) -- servo-ua-cache > | | +--234,496 B (00.10%) -- element-and-pseudos-maps > | | +---59,648 B (00.02%) -- revalidation-selectors > | | +---58,320 B (00.02%) -- invalidation-map > | | +---30,752 B (00.01%) -- other > | | +---10,752 B (00.00%) -- precomputed-pseudos --- components/style/applicable_declarations.rs | 3 + components/style/gecko/generated/bindings.rs | 5 ++ .../style/gecko/generated/structs_debug.rs | 64 ++++++++----------- .../style/gecko/generated/structs_release.rs | 64 ++++++++----------- components/style/selector_parser.rs | 1 + components/style/stylist.rs | 46 +++++++++---- ports/geckolib/glue.rs | 15 ++++- 7 files changed, 114 insertions(+), 84 deletions(-) diff --git a/components/style/applicable_declarations.rs b/components/style/applicable_declarations.rs index ffd2c8ea180..0824b60a0a2 100644 --- a/components/style/applicable_declarations.rs +++ b/components/style/applicable_declarations.rs @@ -36,6 +36,7 @@ const SOURCE_ORDER_MASK: u32 = (1 << SOURCE_ORDER_BITS) - 1; const SOURCE_ORDER_MAX: u32 = SOURCE_ORDER_MASK; /// Stores the source order of a block and the cascade level it belongs to. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Copy, Eq, PartialEq)] struct SourceOrderAndCascadeLevel(u32); @@ -75,10 +76,12 @@ impl Debug for SourceOrderAndCascadeLevel { /// /// This represents the declarations in a given declaration block for a given /// importance. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Debug, PartialEq)] pub struct ApplicableDeclarationBlock { /// The style source, either a style rule, or a property declaration block. + #[cfg_attr(feature = "gecko", ignore_malloc_size_of = "contains Arcs")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] pub source: StyleSource, /// The source order of the block, and the cascade level it belongs to. diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs index 4043d31bfcb..3487ec2f534 100644 --- a/components/style/gecko/generated/bindings.rs +++ b/components/style/gecko/generated/bindings.rs @@ -2089,6 +2089,11 @@ extern "C" { set: RawServoStyleSetBorrowed); } +extern "C" { + pub fn Servo_UACache_AddSizeOf(malloc_size_of: MallocSizeOf, + malloc_enclosing_size_of: MallocSizeOf, + sizes: *mut ServoStyleSetSizes); +} extern "C" { pub fn Servo_StyleContext_AddRef(ctx: ServoStyleContextBorrowed); } diff --git a/components/style/gecko/generated/structs_debug.rs b/components/style/gecko/generated/structs_debug.rs index b269be0c0e8..59807d919eb 100644 --- a/components/style/gecko/generated/structs_debug.rs +++ b/components/style/gecko/generated/structs_debug.rs @@ -4947,17 +4947,16 @@ pub mod root { #[repr(C)] #[derive(Debug, Copy)] pub struct ServoStyleSetSizes { - pub mStylistRuleTree: usize, - pub mStylistPrecomputedPseudos: usize, - pub mStylistElementAndPseudosMaps: usize, - pub mStylistInvalidationMap: usize, - pub mStylistRevalidationSelectors: usize, - pub mStylistOther: usize, + pub mRuleTree: usize, + pub mPrecomputedPseudos: usize, + pub mElementAndPseudosMaps: usize, + pub mInvalidationMap: usize, + pub mRevalidationSelectors: usize, pub mOther: usize, } #[test] fn bindgen_test_layout_ServoStyleSetSizes() { - assert_eq!(::std::mem::size_of::() , 56usize , + assert_eq!(::std::mem::size_of::() , 48usize , concat ! ( "Size of: " , stringify ! ( ServoStyleSetSizes ) )); assert_eq! (::std::mem::align_of::() , 8usize @@ -4966,49 +4965,42 @@ pub mod root { )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistRuleTree as * const _ as usize } , 0usize , + mRuleTree as * const _ as usize } , 0usize , concat ! + ( + "Alignment of field: " , stringify ! ( + ServoStyleSetSizes ) , "::" , stringify ! ( mRuleTree + ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const ServoStyleSetSizes ) ) . + mPrecomputedPseudos as * const _ as usize } , 8usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistRuleTree ) )); + mPrecomputedPseudos ) )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistPrecomputedPseudos as * const _ as usize } , - 8usize , concat ! ( + mElementAndPseudosMaps as * const _ as usize } , + 16usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistPrecomputedPseudos ) )); + mElementAndPseudosMaps ) )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistElementAndPseudosMaps as * const _ as usize } - , 16usize , concat ! ( - "Alignment of field: " , stringify ! ( - ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistElementAndPseudosMaps ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistInvalidationMap as * const _ as usize } , - 24usize , concat ! ( - "Alignment of field: " , stringify ! ( - ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistInvalidationMap ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistRevalidationSelectors as * const _ as usize } - , 32usize , concat ! ( - "Alignment of field: " , stringify ! ( - ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistRevalidationSelectors ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistOther as * const _ as usize } , 40usize , + mInvalidationMap as * const _ as usize } , 24usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistOther ) )); + mInvalidationMap ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const ServoStyleSetSizes ) ) . + mRevalidationSelectors as * const _ as usize } , + 32usize , concat ! ( + "Alignment of field: " , stringify ! ( + ServoStyleSetSizes ) , "::" , stringify ! ( + mRevalidationSelectors ) )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . mOther - as * const _ as usize } , 48usize , concat ! ( + as * const _ as usize } , 40usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( mOther ) )); diff --git a/components/style/gecko/generated/structs_release.rs b/components/style/gecko/generated/structs_release.rs index cb16c36bcb0..dd1e0f487bd 100644 --- a/components/style/gecko/generated/structs_release.rs +++ b/components/style/gecko/generated/structs_release.rs @@ -4867,17 +4867,16 @@ pub mod root { #[repr(C)] #[derive(Debug, Copy)] pub struct ServoStyleSetSizes { - pub mStylistRuleTree: usize, - pub mStylistPrecomputedPseudos: usize, - pub mStylistElementAndPseudosMaps: usize, - pub mStylistInvalidationMap: usize, - pub mStylistRevalidationSelectors: usize, - pub mStylistOther: usize, + pub mRuleTree: usize, + pub mPrecomputedPseudos: usize, + pub mElementAndPseudosMaps: usize, + pub mInvalidationMap: usize, + pub mRevalidationSelectors: usize, pub mOther: usize, } #[test] fn bindgen_test_layout_ServoStyleSetSizes() { - assert_eq!(::std::mem::size_of::() , 56usize , + assert_eq!(::std::mem::size_of::() , 48usize , concat ! ( "Size of: " , stringify ! ( ServoStyleSetSizes ) )); assert_eq! (::std::mem::align_of::() , 8usize @@ -4886,49 +4885,42 @@ pub mod root { )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistRuleTree as * const _ as usize } , 0usize , + mRuleTree as * const _ as usize } , 0usize , concat ! + ( + "Alignment of field: " , stringify ! ( + ServoStyleSetSizes ) , "::" , stringify ! ( mRuleTree + ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const ServoStyleSetSizes ) ) . + mPrecomputedPseudos as * const _ as usize } , 8usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistRuleTree ) )); + mPrecomputedPseudos ) )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistPrecomputedPseudos as * const _ as usize } , - 8usize , concat ! ( + mElementAndPseudosMaps as * const _ as usize } , + 16usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistPrecomputedPseudos ) )); + mElementAndPseudosMaps ) )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistElementAndPseudosMaps as * const _ as usize } - , 16usize , concat ! ( - "Alignment of field: " , stringify ! ( - ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistElementAndPseudosMaps ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistInvalidationMap as * const _ as usize } , - 24usize , concat ! ( - "Alignment of field: " , stringify ! ( - ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistInvalidationMap ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistRevalidationSelectors as * const _ as usize } - , 32usize , concat ! ( - "Alignment of field: " , stringify ! ( - ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistRevalidationSelectors ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ServoStyleSetSizes ) ) . - mStylistOther as * const _ as usize } , 40usize , + mInvalidationMap as * const _ as usize } , 24usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( - mStylistOther ) )); + mInvalidationMap ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const ServoStyleSetSizes ) ) . + mRevalidationSelectors as * const _ as usize } , + 32usize , concat ! ( + "Alignment of field: " , stringify ! ( + ServoStyleSetSizes ) , "::" , stringify ! ( + mRevalidationSelectors ) )); assert_eq! (unsafe { & ( * ( 0 as * const ServoStyleSetSizes ) ) . mOther - as * const _ as usize } , 48usize , concat ! ( + as * const _ as usize } , 40usize , concat ! ( "Alignment of field: " , stringify ! ( ServoStyleSetSizes ) , "::" , stringify ! ( mOther ) )); diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs index f61a7ffed8b..f55161a9cc4 100644 --- a/components/style/selector_parser.rs +++ b/components/style/selector_parser.rs @@ -112,6 +112,7 @@ pub trait ElementExt: Element + Debug { } /// A per-functional-pseudo map, from a given pseudo to a `T`. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct PerPseudoElementMap { entries: [Option; SIMPLE_PSEUDO_COUNT], diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 0cedabb686a..60b3d1b520d 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -17,6 +17,8 @@ use invalidation::element::invalidation_map::InvalidationMap; use invalidation::media_queries::{EffectiveMediaQueryResults, ToMediaListKey}; #[cfg(feature = "gecko")] use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; +#[cfg(feature = "gecko")] +use malloc_size_of::MallocUnconditionalShallowSizeOf; use media_queries::Device; use properties::{self, CascadeFlags, ComputedValues}; use properties::{AnimationRules, PropertyDeclarationBlock}; @@ -133,6 +135,23 @@ impl UserAgentCascadeDataCache { fn clear(&mut self) { self.entries.clear(); } + + #[cfg(feature = "gecko")] + pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { + sizes.mOther += self.entries.shallow_size_of(ops); + for arc in self.entries.iter() { + // These are primary Arc references that can be measured + // unconditionally. + sizes.mOther += arc.unconditional_shallow_size_of(ops); + arc.add_size_of(ops, sizes); + } + } +} + +/// Measure heap usage of UA_CASCADE_DATA_CACHE. +#[cfg(feature = "gecko")] +pub fn add_size_of_ua_cache(ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { + UA_CASCADE_DATA_CACHE.lock().unwrap().add_size_of(ops, sizes); } type PrecomputedPseudoElementDeclarations = @@ -151,6 +170,14 @@ struct UserAgentCascadeData { precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations, } +impl UserAgentCascadeData { + #[cfg(feature = "gecko")] + fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { + self.cascade_data.add_size_of_children(ops, sizes); + sizes.mPrecomputedPseudos += self.precomputed_pseudo_element_decls.size_of(ops); + } +} + /// All the computed information for a stylesheet. #[derive(Default)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -304,9 +331,6 @@ impl DocumentCascadeData { pub fn add_size_of_children(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { self.user.add_size_of_children(ops, sizes); self.author.add_size_of_children(ops, sizes); - - // FIXME(emilio): UA_CASCADE_DATA_CACHE is shared, we should do whatever - // we do for RuleProcessorCache in Gecko. } } @@ -1500,7 +1524,7 @@ impl Stylist { #[cfg(feature = "gecko")] pub fn add_size_of_children(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { self.cascade_data.add_size_of_children(ops, sizes); - sizes.mStylistRuleTree += self.rule_tree.size_of(ops); + sizes.mRuleTree += self.rule_tree.size_of(ops); // We may measure other fields in the future if DMD says it's worth it. } @@ -2194,22 +2218,22 @@ impl CascadeData { /// Measures heap usage. #[cfg(feature = "gecko")] pub fn add_size_of_children(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { - sizes.mStylistElementAndPseudosMaps += self.element_map.size_of(ops); + sizes.mElementAndPseudosMaps += self.element_map.size_of(ops); for elem in self.pseudos_map.iter() { if let Some(ref elem) = *elem { - sizes.mStylistElementAndPseudosMaps += as MallocSizeOf>::size_of(elem, ops); + sizes.mElementAndPseudosMaps += as MallocSizeOf>::size_of(elem, ops); } } - sizes.mStylistOther += self.animations.size_of(ops); + sizes.mOther += self.animations.size_of(ops); - sizes.mStylistInvalidationMap += self.invalidation_map.size_of(ops); + sizes.mInvalidationMap += self.invalidation_map.size_of(ops); - sizes.mStylistRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops); + sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops); - sizes.mStylistOther += self.effective_media_query_results.size_of(ops); - sizes.mStylistOther += self.extra_data.size_of(ops); + sizes.mOther += self.effective_media_query_results.size_of(ops); + sizes.mOther += self.extra_data.size_of(ops); } } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 92735be556c..eda8d6f8b4c 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -131,7 +131,7 @@ use style::stylesheets::{StylesheetContents, SupportsRule}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue}; use style::stylesheets::supports_rule::parse_condition_or_declaration; -use style::stylist::{RuleInclusion, Stylist}; +use style::stylist::{add_size_of_ua_cache, RuleInclusion, Stylist}; use style::thread_state; use style::timer::Timer; use style::traversal::DomTraversal; @@ -3768,6 +3768,19 @@ pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis( data.add_size_of_children(&mut ops, sizes); } +#[no_mangle] +pub extern "C" fn Servo_UACache_AddSizeOf( + malloc_size_of: GeckoMallocSizeOf, + malloc_enclosing_size_of: GeckoMallocSizeOf, + sizes: *mut ServoStyleSetSizes +) { + let mut ops = MallocSizeOfOps::new(malloc_size_of.unwrap(), + malloc_enclosing_size_of.unwrap(), + None); + let sizes = unsafe { sizes.as_mut() }.unwrap(); + add_size_of_ua_cache(&mut ops, sizes); +} + #[no_mangle] pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency( raw_data: RawServoStyleSetBorrowed,