Skip to content

Commit

Permalink
Instrument FreeType allocations.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nnethercote committed Jun 10, 2015
1 parent 93a45c9 commit 1553fad
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 13 deletions.
8 changes: 8 additions & 0 deletions components/gfx/font_context.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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<SpecifiedFontStyle>,
size: Au,
Expand Down
1 change: 1 addition & 0 deletions components/gfx/lib.rs
Expand Up @@ -16,6 +16,7 @@
#[macro_use]
extern crate log;

extern crate alloc;
extern crate azure;
#[macro_use] extern crate bitflags;
extern crate fnv;
Expand Down
81 changes: 68 additions & 13 deletions components/gfx/platform/freetype/font_context.rs
Expand Up @@ -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 {
Expand All @@ -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<FreeTypeLibraryHandle>,
}

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,
Expand All @@ -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 }),
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions components/gfx/platform/macos/font_context.rs
Expand Up @@ -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: ()
Expand All @@ -13,3 +15,9 @@ impl FontContextHandle {
FontContextHandle { ctx: () }
}
}

impl HeapSizeOf for FontContextHandle {
fn heap_size_of_children(&self) -> usize {
0
}
}

0 comments on commit 1553fad

Please sign in to comment.