servo: Merge #18387 - Measure SmallVecs in SelectorMap and InvalidationMap (from nnethercote:measure-smallvec); r=heycam
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 06 Sep 2017 01:39:35 -0500
changeset 428643 9170cac02dae16ca52ba3e656d6b90916015f639
parent 428642 4ef59b77d1cbaeae823261ea84dcba5801057c0d
child 428644 926d1e8e07414f8622933ef61435ad475fad63f4
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs18387
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #18387 - Measure SmallVecs in SelectorMap and InvalidationMap (from nnethercote:measure-smallvec); r=heycam <!-- Please describe your changes on the following line: --> This is another ~300 KiB on the Obama wikipedia page. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because testing is on the Gecko side. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> r? @heycam Source-Repo: https://github.com/servo/servo Source-Revision: 6051e5ed021b10f1ac89a2865765a46f4358f02f
servo/components/style/invalidation/element/invalidation_map.rs
servo/components/style/selector_map.rs
servo/components/style/stylesheets/memory.rs
servo/components/style/stylist.rs
--- a/servo/components/style/invalidation/element/invalidation_map.rs
+++ b/servo/components/style/invalidation/element/invalidation_map.rs
@@ -10,17 +10,17 @@ use element_state::ElementState;
 use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry};
 use selector_parser::SelectorImpl;
 use selectors::attr::NamespaceConstraint;
 use selectors::parser::{Combinator, Component};
 use selectors::parser::{Selector, SelectorIter, SelectorMethods};
 use selectors::visitor::SelectorVisitor;
 use smallvec::SmallVec;
 #[cfg(feature = "gecko")]
-use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOfHash};
+use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOfFn, MallocSizeOfHash, MallocSizeOfVec};
 
 #[cfg(feature = "gecko")]
 /// Gets the element state relevant to the given `:dir` pseudo-class selector.
 pub fn dir_selector_to_state(s: &[u16]) -> ElementState {
     use element_state::{IN_LTR_STATE, IN_RTL_STATE};
 
     // Jump through some hoops to deal with our Box<[u16]> thing.
     const LTR: [u16; 4] = [b'l' as u16, b't' as u16, b'r' as u16, 0];
@@ -287,29 +287,39 @@ impl InvalidationMap {
             }
 
             index += 1; // Account for the combinator.
         }
     }
 
     /// Measures heap usage.
     #[cfg(feature = "gecko")]
-    pub fn malloc_size_of_children(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn)
+    pub fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn,
+                                   malloc_enclosing_size_of: MallocEnclosingSizeOfFn)
                                    -> usize {
         // Currently we measure the HashMap storage, but not things pointed to
         // by keys and values.
         let mut n = 0;
 
         n += self.class_to_selector.malloc_shallow_size_of_hash(malloc_enclosing_size_of);
-        n += self.id_to_selector.malloc_shallow_size_of_hash(malloc_enclosing_size_of);
+        for (_, val) in self.class_to_selector.iter() {
+            n += val.malloc_shallow_size_of_vec(malloc_size_of);
+        }
 
-        n += self.state_affecting_selectors.malloc_size_of_children(malloc_enclosing_size_of);
+        n += self.id_to_selector.malloc_shallow_size_of_hash(malloc_enclosing_size_of);
+        for (_, val) in self.id_to_selector.iter() {
+            n += val.malloc_shallow_size_of_vec(malloc_size_of);
+        }
+
+        n += self.state_affecting_selectors.malloc_size_of_children(malloc_size_of,
+                                                                    malloc_enclosing_size_of);
 
         n += self.other_attribute_affecting_selectors.malloc_size_of_children(
-            malloc_enclosing_size_of);
+            malloc_size_of, malloc_enclosing_size_of);
+
         n
     }
 }
 
 /// A struct that collects invalidations for a given compound selector.
 struct CompoundSelectorDependencyCollector {
     /// The state this compound selector is affected by.
     state: ElementState,
--- a/servo/components/style/selector_map.rs
+++ b/servo/components/style/selector_map.rs
@@ -15,17 +15,17 @@ use pdqsort::sort_by;
 use precomputed_hash::PrecomputedHash;
 use rule_tree::CascadeLevel;
 use selector_parser::SelectorImpl;
 use selectors::matching::{matches_selector, MatchingContext, ElementSelectorFlags};
 use selectors::parser::{Component, Combinator, SelectorIter};
 use smallvec::{SmallVec, VecLike};
 use std::hash::{BuildHasherDefault, Hash, Hasher};
 #[cfg(feature = "gecko")]
-use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOfHash};
+use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOfFn, MallocSizeOfHash, MallocSizeOfVec};
 use stylist::Rule;
 
 /// A hasher implementation that doesn't hash anything, because it expects its
 /// input to be a suitable u32 hash.
 pub struct PrecomputedHasher {
     hash: Option<u32>,
 }
 
@@ -144,26 +144,41 @@ impl<T: 'static> SelectorMap<T> {
 
     /// Returns the number of entries.
     pub fn len(&self) -> usize {
         self.count
     }
 
     /// Measures heap usage.
     #[cfg(feature = "gecko")]
-    pub fn malloc_size_of_children(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn)
+    pub fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn,
+                                   malloc_enclosing_size_of: MallocEnclosingSizeOfFn)
                                    -> usize {
-        // Currently we measure the HashMap storage, but not things pointed to
-        // by keys and values.
+        // Currently we measure the storage used by the HashMaps, and any
+        // heap-allocated SmallVec values, but not things pointed to by the T
+        // elements within the SmallVec values.
+
         let mut n = 0;
+
         n += self.id_hash.malloc_shallow_size_of_hash(malloc_enclosing_size_of);
+        for (_, val) in self.id_hash.iter() {
+            n += val.malloc_shallow_size_of_vec(malloc_size_of);
+        }
+
         n += self.class_hash.malloc_shallow_size_of_hash(malloc_enclosing_size_of);
+        for (_, val) in self.class_hash.iter() {
+            n += val.malloc_shallow_size_of_vec(malloc_size_of);
+        }
+
         n += self.local_name_hash.malloc_shallow_size_of_hash(malloc_enclosing_size_of);
+        for (_, val) in self.local_name_hash.iter() {
+            n += val.malloc_shallow_size_of_vec(malloc_size_of);
+        }
 
-        // We may measure other fields in the future if DMD says it's worth it.
+        n += self.other.malloc_shallow_size_of_vec(malloc_size_of);
 
         n
     }
 }
 
 impl SelectorMap<Rule> {
     /// Append to `rule_list` all Rules in `self` that match element.
     ///
--- a/servo/components/style/stylesheets/memory.rs
+++ b/servo/components/style/stylesheets/memory.rs
@@ -8,16 +8,17 @@
 use gecko_bindings::bindings::Gecko_HaveSeenPtr;
 #[cfg(feature = "gecko")]
 use gecko_bindings::structs::SeenPtrs;
 #[cfg(feature = "gecko")]
 use hash::HashMap;
 #[cfg(feature = "gecko")]
 use servo_arc::Arc;
 use shared_lock::SharedRwLockReadGuard;
+use smallvec::{Array, SmallVec};
 use std::collections::HashSet;
 use std::hash::{BuildHasher, Hash};
 use std::os::raw::c_void;
 
 /// Like gecko_bindings::structs::MallocSizeOf, but without the Option<>
 /// wrapper.
 ///
 /// Note that functions of this type should be called via do_malloc_size_of(),
@@ -150,16 +151,26 @@ pub trait MallocSizeOfVec {
 }
 
 impl<T> MallocSizeOfVec for Vec<T> {
     fn malloc_shallow_size_of_vec(&self, malloc_size_of: MallocSizeOfFn) -> usize {
         unsafe { do_malloc_size_of(malloc_size_of, self.as_ptr()) }
     }
 }
 
+impl<A: Array> MallocSizeOfVec for SmallVec<A> {
+    fn malloc_shallow_size_of_vec(&self, malloc_size_of: MallocSizeOfFn) -> usize {
+        if self.spilled() {
+            unsafe { do_malloc_size_of(malloc_size_of, self.as_ptr()) }
+        } else {
+            0
+        }
+    }
+}
+
 /// Trait for measuring the heap usage of a hash table.
 pub trait MallocSizeOfHash {
     /// Measure shallowly the size of the memory used within a hash table --
     /// anything pointer to by the keys and values must be measured separately,
     /// using iteration.
     fn malloc_shallow_size_of_hash(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn)
                                    -> usize;
 }
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -1951,37 +1951,38 @@ impl CascadeData {
     }
 
     /// Measures heap usage.
     #[cfg(feature = "gecko")]
     pub fn malloc_add_size_of_children(&self, malloc_size_of: MallocSizeOfFn,
                                        malloc_enclosing_size_of: MallocEnclosingSizeOfFn,
                                        sizes: &mut ServoStyleSetSizes) {
         sizes.mStylistElementAndPseudosMaps +=
-            self.element_map.malloc_size_of_children(malloc_enclosing_size_of);
+            self.element_map.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of);
 
         for elem in self.pseudos_map.iter() {
             if let Some(ref elem) = *elem {
                 sizes.mStylistElementAndPseudosMaps +=
                     elem.malloc_shallow_size_of_box(malloc_size_of) +
-                    elem.malloc_size_of_children(malloc_enclosing_size_of)
+                    elem.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of)
             }
         }
 
         sizes.mStylistOther +=
             self.animations.malloc_shallow_size_of_hash(malloc_enclosing_size_of);
         for val in self.animations.values() {
             sizes.mStylistOther += val.malloc_size_of_children(malloc_size_of);
         }
 
         sizes.mStylistInvalidationMap +=
-            self.invalidation_map.malloc_size_of_children(malloc_enclosing_size_of);
+            self.invalidation_map.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of);
 
         sizes.mStylistRevalidationSelectors +=
-            self.selectors_for_cache_revalidation.malloc_size_of_children(malloc_enclosing_size_of);
+            self.selectors_for_cache_revalidation.malloc_size_of_children(malloc_size_of,
+                                                                          malloc_enclosing_size_of);
 
         sizes.mStylistOther +=
             self.effective_media_query_results.malloc_size_of_children(malloc_enclosing_size_of);
     }
 }
 
 impl Default for CascadeData {
     fn default() -> Self {