mirror of
https://github.com/servo/servo.git
synced 2025-08-26 07:38:21 +01:00
fonts: Measure more FontContext heap usage. (#38733)
Replace a hand-written MallocSizeOf implementation with an automatically derived one. This exposes more than 1MB of previously-untracked heap data on servo.org. Testing: Compared about:memory output for servo.org before and after. Part of: #11559 Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
d490c5c06b
commit
9da8142e2a
8 changed files with 59 additions and 32 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -7715,6 +7715,7 @@ dependencies = [
|
||||||
"keyboard-types",
|
"keyboard-types",
|
||||||
"markup5ever",
|
"markup5ever",
|
||||||
"mime",
|
"mime",
|
||||||
|
"parking_lot",
|
||||||
"resvg",
|
"resvg",
|
||||||
"servo_allocator",
|
"servo_allocator",
|
||||||
"servo_arc",
|
"servo_arc",
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -548,7 +549,15 @@ impl Font {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type FontRef = Arc<Font>;
|
#[derive(Clone, MallocSizeOf)]
|
||||||
|
pub struct FontRef(#[conditional_malloc_size_of] pub(crate) Arc<Font>);
|
||||||
|
|
||||||
|
impl Deref for FontRef {
|
||||||
|
type Target = Arc<Font>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A `FontGroup` is a prioritised list of fonts for a given set of font styles. It is used by
|
/// A `FontGroup` is a prioritised list of fonts for a given set of font styles. It is used by
|
||||||
/// `TextRun` to decide which font to render a character with. If none of the fonts listed in the
|
/// `TextRun` to decide which font to render a character with. If none of the fonts listed in the
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::hash::{BuildHasherDefault, Hash, Hasher};
|
use std::hash::{BuildHasherDefault, Hash, Hasher};
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
@ -14,7 +15,6 @@ use compositing_traits::CrossProcessCompositorApi;
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use net_traits::request::{Destination, Referrer, RequestBuilder};
|
use net_traits::request::{Destination, Referrer, RequestBuilder};
|
||||||
use net_traits::{CoreResourceThread, FetchResponseMsg, ResourceThreads, fetch_async};
|
use net_traits::{CoreResourceThread, FetchResponseMsg, ResourceThreads, fetch_async};
|
||||||
|
@ -45,12 +45,25 @@ use crate::{FontData, LowercaseFontFamilyName, PlatformFontMethods, SystemFontSe
|
||||||
|
|
||||||
static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h)
|
static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h)
|
||||||
|
|
||||||
|
#[derive(MallocSizeOf)]
|
||||||
|
struct FontGroupRef(#[conditional_malloc_size_of] Arc<RwLock<FontGroup>>);
|
||||||
|
|
||||||
|
impl Deref for FontGroupRef {
|
||||||
|
type Target = Arc<RwLock<FontGroup>>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The FontContext represents the per-thread/thread state necessary for
|
/// The FontContext represents the per-thread/thread state necessary for
|
||||||
/// working with fonts. It is the public API used by the layout and
|
/// working with fonts. It is the public API used by the layout and
|
||||||
/// paint code. It talks directly to the system font service where
|
/// paint code. It talks directly to the system font service where
|
||||||
/// required.
|
/// required.
|
||||||
|
#[derive(MallocSizeOf)]
|
||||||
pub struct FontContext {
|
pub struct FontContext {
|
||||||
|
#[conditional_malloc_size_of]
|
||||||
system_font_service_proxy: Arc<SystemFontServiceProxy>,
|
system_font_service_proxy: Arc<SystemFontServiceProxy>,
|
||||||
|
|
||||||
resource_threads: Mutex<CoreResourceThread>,
|
resource_threads: Mutex<CoreResourceThread>,
|
||||||
|
|
||||||
/// A sender that can send messages and receive replies from the compositor.
|
/// A sender that can send messages and receive replies from the compositor.
|
||||||
|
@ -64,7 +77,7 @@ pub struct FontContext {
|
||||||
/// resolved [`FontGroup`] which contains information about all fonts that
|
/// resolved [`FontGroup`] which contains information about all fonts that
|
||||||
/// can be selected with that style.
|
/// can be selected with that style.
|
||||||
resolved_font_groups:
|
resolved_font_groups:
|
||||||
RwLock<HashMap<FontGroupCacheKey, Arc<RwLock<FontGroup>>, BuildHasherDefault<FnvHasher>>>,
|
RwLock<HashMap<FontGroupCacheKey, FontGroupRef, BuildHasherDefault<FnvHasher>>>,
|
||||||
|
|
||||||
web_fonts: CrossThreadFontStore,
|
web_fonts: CrossThreadFontStore,
|
||||||
|
|
||||||
|
@ -83,26 +96,6 @@ pub struct FontContext {
|
||||||
have_removed_web_fonts: AtomicBool,
|
have_removed_web_fonts: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MallocSizeOf for FontContext {
|
|
||||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
|
||||||
let font_cache_size = self
|
|
||||||
.fonts
|
|
||||||
.read()
|
|
||||||
.iter()
|
|
||||||
.map(|(key, font)| {
|
|
||||||
key.size_of(ops) + font.as_ref().map_or(0, |font| (*font).size_of(ops))
|
|
||||||
})
|
|
||||||
.sum::<usize>();
|
|
||||||
let font_group_cache_size = self
|
|
||||||
.resolved_font_groups
|
|
||||||
.read()
|
|
||||||
.iter()
|
|
||||||
.map(|(key, font_group)| key.size_of(ops) + (*font_group.read()).size_of(ops))
|
|
||||||
.sum::<usize>();
|
|
||||||
font_cache_size + font_group_cache_size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FontContext {
|
impl FontContext {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
system_font_service_proxy: Arc<SystemFontServiceProxy>,
|
system_font_service_proxy: Arc<SystemFontServiceProxy>,
|
||||||
|
@ -116,7 +109,7 @@ impl FontContext {
|
||||||
compositor_api: Mutex::new(compositor_api),
|
compositor_api: Mutex::new(compositor_api),
|
||||||
fonts: Default::default(),
|
fonts: Default::default(),
|
||||||
resolved_font_groups: Default::default(),
|
resolved_font_groups: Default::default(),
|
||||||
web_fonts: Arc::new(RwLock::default()),
|
web_fonts: Default::default(),
|
||||||
webrender_font_keys: RwLock::default(),
|
webrender_font_keys: RwLock::default(),
|
||||||
webrender_font_instance_keys: RwLock::default(),
|
webrender_font_instance_keys: RwLock::default(),
|
||||||
have_removed_web_fonts: AtomicBool::new(false),
|
have_removed_web_fonts: AtomicBool::new(false),
|
||||||
|
@ -152,7 +145,7 @@ impl FontContext {
|
||||||
) -> Arc<RwLock<FontGroup>> {
|
) -> Arc<RwLock<FontGroup>> {
|
||||||
let cache_key = FontGroupCacheKey { size, style };
|
let cache_key = FontGroupCacheKey { size, style };
|
||||||
if let Some(font_group) = self.resolved_font_groups.read().get(&cache_key) {
|
if let Some(font_group) = self.resolved_font_groups.read().get(&cache_key) {
|
||||||
return font_group.clone();
|
return font_group.0.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut descriptor = FontDescriptor::from(&*cache_key.style);
|
let mut descriptor = FontDescriptor::from(&*cache_key.style);
|
||||||
|
@ -161,7 +154,7 @@ impl FontContext {
|
||||||
let font_group = Arc::new(RwLock::new(FontGroup::new(&cache_key.style, descriptor)));
|
let font_group = Arc::new(RwLock::new(FontGroup::new(&cache_key.style, descriptor)));
|
||||||
self.resolved_font_groups
|
self.resolved_font_groups
|
||||||
.write()
|
.write()
|
||||||
.insert(cache_key, font_group.clone());
|
.insert(cache_key, FontGroupRef(font_group.clone()));
|
||||||
font_group
|
font_group
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,12 +268,12 @@ impl FontContext {
|
||||||
font_descriptor: FontDescriptor,
|
font_descriptor: FontDescriptor,
|
||||||
synthesized_small_caps: Option<FontRef>,
|
synthesized_small_caps: Option<FontRef>,
|
||||||
) -> Result<FontRef, &'static str> {
|
) -> Result<FontRef, &'static str> {
|
||||||
Ok(Arc::new(Font::new(
|
Ok(FontRef(Arc::new(Font::new(
|
||||||
font_template.clone(),
|
font_template.clone(),
|
||||||
font_descriptor.clone(),
|
font_descriptor.clone(),
|
||||||
self.get_font_data(&font_template.identifier()),
|
self.get_font_data(&font_template.identifier()),
|
||||||
synthesized_small_caps,
|
synthesized_small_caps,
|
||||||
)?))
|
)?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_font_instance_key(&self, font: &Font) -> FontInstanceKey {
|
pub(crate) fn create_font_instance_key(&self, font: &Font) -> FontInstanceKey {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
@ -21,7 +22,16 @@ pub struct FontStore {
|
||||||
web_fonts_loading_for_stylesheets: Vec<(DocumentStyleSheet, usize)>,
|
web_fonts_loading_for_stylesheets: Vec<(DocumentStyleSheet, usize)>,
|
||||||
web_fonts_loading_for_script: usize,
|
web_fonts_loading_for_script: usize,
|
||||||
}
|
}
|
||||||
pub(crate) type CrossThreadFontStore = Arc<RwLock<FontStore>>;
|
|
||||||
|
#[derive(Default, MallocSizeOf)]
|
||||||
|
pub(crate) struct CrossThreadFontStore(#[conditional_malloc_size_of] Arc<RwLock<FontStore>>);
|
||||||
|
|
||||||
|
impl Deref for CrossThreadFontStore {
|
||||||
|
type Target = Arc<RwLock<FontStore>>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FontStore {
|
impl FontStore {
|
||||||
pub(crate) fn clear(&mut self) {
|
pub(crate) fn clear(&mut self) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ pub use font_store::*;
|
||||||
pub use font_template::*;
|
pub use font_template::*;
|
||||||
pub use glyph::*;
|
pub use glyph::*;
|
||||||
use ipc_channel::ipc::IpcSharedMemory;
|
use ipc_channel::ipc::IpcSharedMemory;
|
||||||
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
pub use platform::LocalFontIdentifier;
|
pub use platform::LocalFontIdentifier;
|
||||||
pub use shaper::*;
|
pub use shaper::*;
|
||||||
pub use system_font_service::*;
|
pub use system_font_service::*;
|
||||||
|
@ -30,8 +31,8 @@ use unicode_properties::{EmojiStatus, UnicodeEmoji, emoji};
|
||||||
/// A data structure to store data for fonts. Data is stored internally in an
|
/// A data structure to store data for fonts. Data is stored internally in an
|
||||||
/// [`IpcSharedMemory`] handle, so that it can be send without serialization
|
/// [`IpcSharedMemory`] handle, so that it can be send without serialization
|
||||||
/// across IPC channels.
|
/// across IPC channels.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, MallocSizeOf)]
|
||||||
pub struct FontData(pub(crate) Arc<IpcSharedMemory>);
|
pub struct FontData(#[conditional_malloc_size_of] pub(crate) Arc<IpcSharedMemory>);
|
||||||
|
|
||||||
impl FontData {
|
impl FontData {
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Self {
|
pub fn from_bytes(bytes: &[u8]) -> Self {
|
||||||
|
|
|
@ -363,7 +363,7 @@ struct FontTemplateCacheKey {
|
||||||
|
|
||||||
/// The public interface to the [`SystemFontService`], used by per-Document
|
/// The public interface to the [`SystemFontService`], used by per-Document
|
||||||
/// `FontContext` instances.
|
/// `FontContext` instances.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub struct SystemFontServiceProxy {
|
pub struct SystemFontServiceProxy {
|
||||||
sender: Mutex<IpcSender<SystemFontServiceMessage>>,
|
sender: Mutex<IpcSender<SystemFontServiceMessage>>,
|
||||||
templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>,
|
templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>,
|
||||||
|
|
|
@ -23,6 +23,7 @@ ipc-channel = { workspace = true }
|
||||||
keyboard-types = { workspace = true }
|
keyboard-types = { workspace = true }
|
||||||
markup5ever = { workspace = true }
|
markup5ever = { workspace = true }
|
||||||
mime = { workspace = true }
|
mime = { workspace = true }
|
||||||
|
parking_lot = { workspace = true }
|
||||||
resvg = { workspace = true }
|
resvg = { workspace = true }
|
||||||
servo_allocator = { path = "../allocator" }
|
servo_allocator = { path = "../allocator" }
|
||||||
servo_arc = { workspace = true }
|
servo_arc = { workspace = true }
|
||||||
|
|
|
@ -613,6 +613,18 @@ impl<T: MallocSizeOf> MallocSizeOf for std::sync::Mutex<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: MallocSizeOf> MallocSizeOf for parking_lot::Mutex<T> {
|
||||||
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
(*self.lock()).size_of(ops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: MallocSizeOf> MallocSizeOf for parking_lot::RwLock<T> {
|
||||||
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
(*self.read()).size_of(ops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: MallocSizeOf, Unit> MallocSizeOf for euclid::Length<T, Unit> {
|
impl<T: MallocSizeOf, Unit> MallocSizeOf for euclid::Length<T, Unit> {
|
||||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
self.0.size_of(ops)
|
self.0.size_of(ops)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue