mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #17953 - nnethercote:bug-1383977, r=Manishearth
stylo: Measure Elements and ComputedValues. This is for https://bugzilla.mozilla.org/show_bug.cgi?id=1383977. <!-- Please describe your changes on the following line: --> The patch provides FFI access to Gecko's SeenPtrs type from Rust, in order to record what has already been measured when measuring Arcs. (The SeenPtrs must be initialized on the Gecko side because the same table is reused for measuring all Elements within a window, because Elements can share ComputedValues.) I have confirmed with DMD that this is working correctly. The patch also introduces MallocSizeOfRepeats, which is like MallocSizeOf but takes a SizeOfState, which holds a SeenPtrs table. --- <!-- 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 - [X] 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 done on mozilla-central CI. <!-- 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. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17953) <!-- Reviewable:end -->
This commit is contained in:
commit
32e2e546ac
9 changed files with 161 additions and 5 deletions
|
@ -41,6 +41,7 @@ use std::hash::{Hash, Hasher};
|
|||
use std::iter::{ExactSizeIterator, Iterator};
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::c_void;
|
||||
use std::process;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
@ -200,6 +201,7 @@ impl<T> Arc<T> {
|
|||
pub fn borrow_arc<'a>(&'a self) -> ArcBorrow<'a, T> {
|
||||
ArcBorrow(&**self)
|
||||
}
|
||||
|
||||
/// Temporarily converts |self| into a bonafide RawOffsetArc and exposes it to the
|
||||
/// provided callback. The refcount is not modified.
|
||||
#[inline(always)]
|
||||
|
@ -218,6 +220,12 @@ impl<T> Arc<T> {
|
|||
// Forward the result.
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns the address on the heap of the Arc itself -- not the T within it -- for memory
|
||||
/// reporting.
|
||||
pub fn heap_ptr(&self) -> *const c_void {
|
||||
self.p.ptr() as *const ArcInner<T> as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
|
|
|
@ -15,6 +15,8 @@ use servo_arc::Arc;
|
|||
use shared_lock::StylesheetGuards;
|
||||
use std::fmt;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
#[cfg(feature = "gecko")]
|
||||
use stylesheets::{MallocSizeOfWithRepeats, SizeOfState};
|
||||
|
||||
bitflags! {
|
||||
flags RestyleFlags: u8 {
|
||||
|
@ -242,6 +244,20 @@ impl fmt::Debug for ElementStyles {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl MallocSizeOfWithRepeats for ElementStyles {
|
||||
fn malloc_size_of_children(&self, state: &mut SizeOfState) -> usize {
|
||||
let mut n = 0;
|
||||
if let Some(ref primary) = self.primary {
|
||||
n += primary.malloc_size_of_children(state)
|
||||
};
|
||||
|
||||
// We may measure more fields in the future if DMD says it's worth it.
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
/// Style system data associated with an Element.
|
||||
///
|
||||
/// In Gecko, this hangs directly off the Element. Servo, this is embedded
|
||||
|
@ -392,3 +408,14 @@ impl ElementData {
|
|||
self.restyle.clear_flags_and_damage();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl MallocSizeOfWithRepeats for ElementData {
|
||||
fn malloc_size_of_children(&self, state: &mut SizeOfState) -> usize {
|
||||
let n = self.styles.malloc_size_of_children(state);
|
||||
|
||||
// We may measure more fields in the future if DMD says it's worth it.
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use gecko_bindings::structs::mozilla::css::ImageValue;
|
|||
use gecko_bindings::structs::mozilla::css::URLValue;
|
||||
use gecko_bindings::structs::mozilla::css::URLValueData;
|
||||
use gecko_bindings::structs::mozilla::MallocSizeOf;
|
||||
use gecko_bindings::structs::mozilla::SeenPtrs;
|
||||
use gecko_bindings::structs::mozilla::Side;
|
||||
use gecko_bindings::structs::nsIContent;
|
||||
use gecko_bindings::structs::nsIDocument;
|
||||
|
@ -1081,6 +1082,10 @@ extern "C" {
|
|||
extern "C" {
|
||||
pub fn Gecko_DropElementSnapshot(snapshot: ServoElementSnapshotOwned);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_HaveSeenPtr(table: *mut SeenPtrs, ptr: *const ::std::os::raw::c_void)
|
||||
-> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_ResizeTArrayForStrings(array: *mut nsTArray<nsStringRepr>,
|
||||
length: u32);
|
||||
|
@ -1878,6 +1883,11 @@ extern "C" {
|
|||
extern "C" {
|
||||
pub fn Servo_Element_ClearData(node: RawGeckoElementBorrowed);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_Element_SizeOfExcludingThis(malloc_size_of: MallocSizeOf,
|
||||
seen_ptrs: *mut SeenPtrs,
|
||||
node: RawGeckoElementBorrowed) -> usize;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
|
||||
gecko_stylesheet:
|
||||
|
|
|
@ -6024,6 +6024,21 @@ pub mod root {
|
|||
MAX = 29,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct SeenPtrs {
|
||||
pub _bindgen_opaque_blob: [u64; 6usize],
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_SeenPtrs() {
|
||||
assert_eq!(::std::mem::size_of::<SeenPtrs>() , 48usize , concat !
|
||||
( "Size of: " , stringify ! ( SeenPtrs ) ));
|
||||
assert_eq! (::std::mem::align_of::<SeenPtrs>() , 8usize , concat !
|
||||
( "Alignment of " , stringify ! ( SeenPtrs ) ));
|
||||
}
|
||||
impl Clone for SeenPtrs {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct URLExtraData {
|
||||
pub mRefCnt: root::mozilla::ThreadSafeAutoRefCnt,
|
||||
|
|
|
@ -5906,6 +5906,21 @@ pub mod root {
|
|||
MAX = 29,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct SeenPtrs {
|
||||
pub _bindgen_opaque_blob: [u64; 5usize],
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_SeenPtrs() {
|
||||
assert_eq!(::std::mem::size_of::<SeenPtrs>() , 40usize , concat !
|
||||
( "Size of: " , stringify ! ( SeenPtrs ) ));
|
||||
assert_eq! (::std::mem::align_of::<SeenPtrs>() , 8usize , concat !
|
||||
( "Alignment of " , stringify ! ( SeenPtrs ) ));
|
||||
}
|
||||
impl Clone for SeenPtrs {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct URLExtraData {
|
||||
pub mRefCnt: root::mozilla::ThreadSafeAutoRefCnt,
|
||||
|
|
|
@ -60,6 +60,7 @@ use selector_parser::PseudoElement;
|
|||
use servo_arc::{Arc, RawOffsetArc};
|
||||
use std::mem::{forget, uninitialized, transmute, zeroed};
|
||||
use std::{cmp, ops, ptr};
|
||||
use stylesheets::{MallocSizeOfWithRepeats, SizeOfState};
|
||||
use values::{self, Auto, CustomIdent, Either, KeyframesName};
|
||||
use values::computed::ToComputedValue;
|
||||
use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
|
||||
|
@ -308,6 +309,11 @@ impl ComputedValuesInner {
|
|||
self.visited_style.as_ref().map(|x| &**x)
|
||||
}
|
||||
|
||||
/// Gets the raw visited style. Useful for memory reporting.
|
||||
pub fn get_raw_visited_style(&self) -> &Option<RawOffsetArc<ComputedValues>> {
|
||||
&self.visited_style
|
||||
}
|
||||
|
||||
/// Gets a reference to the visited style. Panic if no visited style exists.
|
||||
pub fn visited_style(&self) -> &ComputedValues {
|
||||
self.get_visited_style().unwrap()
|
||||
|
@ -364,6 +370,18 @@ impl ComputedValuesInner {
|
|||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOfWithRepeats for ComputedValues {
|
||||
fn malloc_size_of_children(&self, state: &mut SizeOfState) -> usize {
|
||||
let mut n = 0;
|
||||
if let Some(ref raw_offset_arc) = *self.get_raw_visited_style() {
|
||||
n += raw_offset_arc.with_arc(|a: &Arc<ComputedValues>| {
|
||||
a.malloc_size_of_children(state)
|
||||
})
|
||||
}
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
<%def name="declare_style_struct(style_struct)">
|
||||
pub use ::gecko_bindings::structs::mozilla::Gecko${style_struct.gecko_name} as ${style_struct.gecko_struct_name};
|
||||
impl ${style_struct.gecko_struct_name} {
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
//! Memory reporting for the style system when running inside of Gecko.
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
use gecko_bindings::bindings::Gecko_HaveSeenPtr;
|
||||
#[cfg(feature = "gecko")]
|
||||
use gecko_bindings::structs::SeenPtrs;
|
||||
#[cfg(feature = "gecko")]
|
||||
use servo_arc::Arc;
|
||||
use shared_lock::SharedRwLockReadGuard;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
|
@ -14,11 +20,24 @@ use std::os::raw::c_void;
|
|||
/// do_malloc_size_of(), rather than directly.
|
||||
pub type MallocSizeOfFn = unsafe extern "C" fn(ptr: *const c_void) -> usize;
|
||||
|
||||
/// Servo-side counterpart to mozilla::SizeOfState. The only difference is that
|
||||
/// this struct doesn't contain the SeenPtrs table, just a pointer to it.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub struct SizeOfState {
|
||||
/// Function that measures the size of heap blocks.
|
||||
pub malloc_size_of: MallocSizeOfFn,
|
||||
/// Table recording heap blocks that have already been measured.
|
||||
pub seen_ptrs: *mut SeenPtrs,
|
||||
}
|
||||
|
||||
/// Call malloc_size_of on ptr, first checking that the allocation isn't empty.
|
||||
pub unsafe fn is_empty<T>(ptr: *const T) -> bool {
|
||||
return ptr as usize <= ::std::mem::align_of::<T>();
|
||||
}
|
||||
|
||||
/// Call malloc_size_of on ptr, first checking that the allocation isn't empty.
|
||||
pub unsafe fn do_malloc_size_of<T>(malloc_size_of: MallocSizeOfFn, ptr: *const T) -> usize {
|
||||
use std::mem::align_of;
|
||||
|
||||
if ptr as usize <= align_of::<T>() {
|
||||
if is_empty(ptr) {
|
||||
0
|
||||
} else {
|
||||
malloc_size_of(ptr as *const c_void)
|
||||
|
@ -32,6 +51,15 @@ pub trait MallocSizeOf {
|
|||
fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize;
|
||||
}
|
||||
|
||||
/// Like MallocSizeOf, but takes a SizeOfState which allows it to measure
|
||||
/// graph-like structures such as those containing Arcs.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub trait MallocSizeOfWithRepeats {
|
||||
/// Measure the size of any heap-allocated structures that hang off this
|
||||
/// value, but not the space taken up by the value itself.
|
||||
fn malloc_size_of_children(&self, state: &mut SizeOfState) -> usize;
|
||||
}
|
||||
|
||||
/// Like MallocSizeOf, but operates with the global SharedRwLockReadGuard
|
||||
/// locked.
|
||||
pub trait MallocSizeOfWithGuard {
|
||||
|
@ -58,6 +86,19 @@ impl<T: MallocSizeOf> MallocSizeOf for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
impl<T: MallocSizeOfWithRepeats> MallocSizeOfWithRepeats for Arc<T> {
|
||||
fn malloc_size_of_children(&self, state: &mut SizeOfState) -> usize {
|
||||
let mut n = 0;
|
||||
let heap_ptr = self.heap_ptr();
|
||||
if unsafe { !is_empty(heap_ptr) && !Gecko_HaveSeenPtr(state.seen_ptrs, heap_ptr) } {
|
||||
n += unsafe { (state.malloc_size_of)(heap_ptr) };
|
||||
n += (**self).malloc_size_of_children(state);
|
||||
}
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MallocSizeOfWithGuard> MallocSizeOfWithGuard for Vec<T> {
|
||||
fn malloc_size_of_children(
|
||||
&self,
|
||||
|
|
|
@ -40,6 +40,8 @@ pub use self::keyframes_rule::KeyframesRule;
|
|||
pub use self::loader::StylesheetLoader;
|
||||
pub use self::media_rule::MediaRule;
|
||||
pub use self::memory::{MallocSizeOf, MallocSizeOfFn, MallocSizeOfWithGuard};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::memory::{MallocSizeOfWithRepeats, SizeOfState};
|
||||
pub use self::namespace_rule::NamespaceRule;
|
||||
pub use self::page_rule::PageRule;
|
||||
pub use self::rule_parser::{State, TopLevelRuleParser};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue