servo: Merge #6309 - Instrument FreeType allocations (from nnethercote:instrument-freetype); r=glennw

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.

Source-Repo: https://github.com/servo/servo
Source-Revision: fdeebf86a1424e9fffa122efa08fe397f6e7cd7d
This commit is contained in:
Nicholas Nethercote 2015-06-10 16:53:55 -06:00
Родитель 172144e575
Коммит 679452a543
4 изменённых файлов: 85 добавлений и 13 удалений

Просмотреть файл

@ -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<SpecifiedFontStyle>,
size: Au,

Просмотреть файл

@ -16,6 +16,7 @@
#[macro_use]
extern crate log;
extern crate alloc;
extern crate azure;
#[macro_use] extern crate bitflags;
extern crate fnv;

Просмотреть файл

@ -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<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,
@ -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 }),
}
}
}

Просмотреть файл

@ -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
}
}