From 1553fada53115f58c86113b43b799615f4025b08 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 8 Jun 2015 20:38:01 -0700 Subject: [PATCH] Instrument FreeType allocations. This will allow reporting of memory usage by FreeType instances, which are measured in the MiBs for LayoutWorker threads. This change also makes FreeType allocations happen with jemalloc instead of the system malloc, which is a good thing. Finally, the change documents some dubiousness involving FontContextHandle. --- components/gfx/font_context.rs | 8 ++ components/gfx/lib.rs | 1 + .../gfx/platform/freetype/font_context.rs | 81 ++++++++++++++++--- components/gfx/platform/macos/font_context.rs | 8 ++ 4 files changed, 85 insertions(+), 13 deletions(-) diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index 4201e2ddc5f1..27ba6c493df1 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -16,6 +16,7 @@ use platform::font_template::FontTemplateData; use smallvec::SmallVec8; use util::cache::HashCache; use util::geometry::Au; +use util::mem::HeapSizeOf; use std::borrow::{self, ToOwned}; use std::cell::RefCell; @@ -285,6 +286,13 @@ impl FontContext { } } +impl HeapSizeOf for FontContext { + fn heap_size_of_children(&self) -> usize { + // FIXME(njn): Measure other fields eventually. + self.platform_handle.heap_size_of_children() + } +} + struct LayoutFontGroupCacheKey { pointer: Arc, size: Au, diff --git a/components/gfx/lib.rs b/components/gfx/lib.rs index 9465fcc871ff..3117c8f7a6d8 100644 --- a/components/gfx/lib.rs +++ b/components/gfx/lib.rs @@ -16,6 +16,7 @@ #[macro_use] extern crate log; +extern crate alloc; extern crate azure; #[macro_use] extern crate bitflags; extern crate fnv; diff --git a/components/gfx/platform/freetype/font_context.rs b/components/gfx/platform/freetype/font_context.rs index c60c6bf5e363..b8b70c2b42e1 100644 --- a/components/gfx/platform/freetype/font_context.rs +++ b/components/gfx/platform/freetype/font_context.rs @@ -10,35 +10,72 @@ use freetype::freetype::FT_Memory; use freetype::freetype::FT_New_Library; use freetype::freetype::struct_FT_MemoryRec_; +use alloc::heap; use std::ptr; use std::rc::Rc; +use util::mem::{HeapSizeOf, heap_size_of}; -use libc::{self, c_void, c_long, size_t}; +use libc::{c_void, c_long}; -extern fn ft_alloc(_mem: FT_Memory, size: c_long) -> *mut c_void { +// We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is +// created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to +// record the memory usage of each FreeType instance. +struct User { + size: usize, +} + +// FreeType doesn't require any particular alignment for allocations. +const FT_ALIGNMENT: usize = 0; + +extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void { unsafe { - let ptr = libc::malloc(size as size_t); - ptr as *mut c_void + let ptr = heap::allocate(req_size as usize, FT_ALIGNMENT) as *mut c_void; + let actual_size = heap_size_of(ptr); + + let user = (*mem).user as *mut User; + (*user).size += actual_size; + + ptr } } -extern fn ft_free(_mem: FT_Memory, block: *mut c_void) { +extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) { unsafe { - libc::free(block); + let actual_size = heap_size_of(ptr); + + let user = (*mem).user as *mut User; + (*user).size -= actual_size; + + heap::deallocate(ptr as *mut u8, actual_size, FT_ALIGNMENT); } } -extern fn ft_realloc(_mem: FT_Memory, _cur_size: c_long, new_size: c_long, block: *mut c_void) -> *mut c_void { +extern fn ft_realloc(mem: FT_Memory, _cur_size: c_long, new_req_size: c_long, + old_ptr: *mut c_void) -> *mut c_void { unsafe { - let ptr = libc::realloc(block, new_size as size_t); - ptr as *mut c_void + let old_actual_size = heap_size_of(old_ptr); + let new_ptr = heap::reallocate(old_ptr as *mut u8, old_actual_size, + new_req_size as usize, FT_ALIGNMENT) as *mut c_void; + let new_actual_size = heap_size_of(new_ptr); + + let user = (*mem).user as *mut User; + (*user).size += new_actual_size - old_actual_size; + + new_ptr } } +// A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from +// rustc. But using a typedef avoids this, so... +pub type UserPtr = *mut User; + +// WARNING: We need to be careful how we use this struct. See the comment about Rc<> in +// FontContextHandle. #[derive(Clone)] pub struct FreeTypeLibraryHandle { pub ctx: FT_Library, - pub mem: FT_Memory, + mem: FT_Memory, + user: UserPtr, } impl Drop for FreeTypeLibraryHandle { @@ -47,19 +84,37 @@ impl Drop for FreeTypeLibraryHandle { unsafe { FT_Done_Library(self.ctx); Box::from_raw(self.mem); + Box::from_raw(self.user); } } } -#[derive(Clone)] +impl HeapSizeOf for FreeTypeLibraryHandle { + fn heap_size_of_children(&self) -> usize { + let ft_size = unsafe { (*self.user).size }; + ft_size + + heap_size_of(self.ctx as *const c_void) + + heap_size_of(self.mem as *const c_void) + + heap_size_of(self.user as *const c_void) + } +} + +#[derive(Clone, HeapSizeOf)] pub struct FontContextHandle { + // WARNING: FreeTypeLibraryHandle contains raw pointers, is clonable, and also implements + // `Drop`. This field needs to be Rc<> to make sure that the `drop` function is only called + // once, otherwise we'll get crashes. Yuk. pub ctx: Rc, } impl FontContextHandle { pub fn new() -> FontContextHandle { + let user = box User { + size: 0, + }; + let user: *mut User = ::std::boxed::into_raw(user); let mem = box struct_FT_MemoryRec_ { - user: ptr::null_mut(), + user: user as *mut c_void, alloc: ft_alloc, free: ft_free, realloc: ft_realloc, @@ -74,7 +129,7 @@ impl FontContextHandle { FT_Add_Default_Modules(ctx); FontContextHandle { - ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem }), + ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem, user: user }), } } } diff --git a/components/gfx/platform/macos/font_context.rs b/components/gfx/platform/macos/font_context.rs index e35aadb9910a..ca718de09ca1 100644 --- a/components/gfx/platform/macos/font_context.rs +++ b/components/gfx/platform/macos/font_context.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use util::mem::HeapSizeOf; + #[derive(Clone)] pub struct FontContextHandle { ctx: () @@ -13,3 +15,9 @@ impl FontContextHandle { FontContextHandle { ctx: () } } } + +impl HeapSizeOf for FontContextHandle { + fn heap_size_of_children(&self) -> usize { + 0 + } +}