Refactor common infrastructure for creating memory reports. (#36579)

This removes a bunch of duplicated code needed to support
ConditionalMallocSizeOf correctly, and fixes multiple places where that
code was subtly wrong (the seen pointers hashset was never cleared).

Testing: Measuring https://www.nist.gov/image-gallery lots of times.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-04-17 22:14:49 -04:00 committed by GitHub
parent 2a81987590
commit 5e2d42e944
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 68 additions and 57 deletions

View file

@ -8,8 +8,7 @@
#![allow(dead_code)]
use core::ffi::c_char;
use std::cell::{Cell, LazyCell, RefCell};
use std::collections::HashSet;
use std::cell::Cell;
use std::ffi::CString;
use std::io::{Write, stdout};
use std::ops::Deref;
@ -818,9 +817,7 @@ fn in_range<T: PartialOrd + Copy>(val: T, min: T, max: T) -> Option<T> {
}
}
thread_local!(static SEEN_POINTERS: LazyCell<RefCell<HashSet<*const c_void>>> = const {
LazyCell::new(|| RefCell::new(HashSet::new()))
});
thread_local!(static MALLOC_SIZE_OF_OPS: Cell<*mut MallocSizeOfOps> = const { Cell::new(ptr::null_mut()) });
#[allow(unsafe_code)]
unsafe extern "C" fn get_size(obj: *mut JSObject) -> usize {
@ -831,14 +828,8 @@ unsafe extern "C" fn get_size(obj: *mut JSObject) -> usize {
if dom_object.is_null() {
return 0;
}
let seen_pointer =
move |ptr| SEEN_POINTERS.with(|pointers| !pointers.borrow_mut().insert(ptr));
let mut ops = MallocSizeOfOps::new(
servo_allocator::usable_size,
None,
Some(Box::new(seen_pointer)),
);
(v.malloc_size_of)(&mut ops, dom_object)
let ops = MALLOC_SIZE_OF_OPS.get();
(v.malloc_size_of)(&mut *ops, dom_object)
},
Err(_e) => 0,
}
@ -943,13 +934,13 @@ pub(crate) use script_bindings::script_runtime::JSContext;
/// Extra methods for the JSContext type defined in script_bindings, when
/// the methods are only called by code in the script crate.
pub(crate) trait JSContextHelper {
fn get_reports(&self, path_seg: String) -> Vec<Report>;
fn get_reports(&self, path_seg: String, ops: &mut MallocSizeOfOps) -> Vec<Report>;
}
impl JSContextHelper for JSContext {
#[allow(unsafe_code)]
fn get_reports(&self, path_seg: String) -> Vec<Report> {
SEEN_POINTERS.with(|pointers| pointers.borrow_mut().clear());
fn get_reports(&self, path_seg: String, ops: &mut MallocSizeOfOps) -> Vec<Report> {
MALLOC_SIZE_OF_OPS.with(|ops_tls| ops_tls.set(ops));
let stats = unsafe {
let mut stats = ::std::mem::zeroed();
if !CollectServoSizes(**self, &mut stats, Some(get_size)) {
@ -957,6 +948,7 @@ impl JSContextHelper for JSContext {
}
stats
};
MALLOC_SIZE_OF_OPS.with(|ops| ops.set(ptr::null_mut()));
let mut reports = vec![];
let mut report = |mut path_suffix, kind, size| {