Add memory reporting infrastructure and use it to measure the display list.

This changeset implements the beginnings of fine-grained measurement of
Servo's data structures.

- It adds a new `SizeOf` trait, which is used to measure the memory used
  by heap data structures, and implements it for some std types: Box,
  String, Option, Arc, Vec, and DList.

- It adds a new `MemoryReporter` trait which is used to report memory
  measurements from other threads to the memory profiler. Reporters are
  registered and unregistered with the memory profiler, and the memory
  profiler makes measurement requests of reporters when necessary.

- It plumbs a MemoryProfilerChan through to the layout task so it can
  register a memory reporter.

- It implements the `SizeOf` trait for `DisplayList` and associated
  types, and adds a memory reporter that uses it.

The display list hits 14.77 MiB when viewing
tests/html/perf-rainbow.html, and 2.51 MiB when viewing the Guardians of
the Galaxy Wikipedia page from servo-static-suite. Example output:

  0.29: display-list::http://www.reddit.com/
  0.00: display-list::http://static.adzerk.net/reddit/ads.html?sr=-reddit.com,loggedout&bust2#http://www.reddit.com
  0.00: display-list::http://www.reddit.com/static/createadframe.html

There are a number of FIXME comments indicating sub-optimal things. This
is a big enough change for now that doing them as follow-ups seems best.
This commit is contained in:
Nicholas Nethercote 2015-03-10 21:01:05 -07:00
parent 5865d5f717
commit ece2711185
14 changed files with 453 additions and 14 deletions

View file

@ -37,6 +37,7 @@ use net::image::base::Image;
use util::cursor::Cursor;
use util::dlist as servo_dlist;
use util::geometry::{self, Au, MAX_RECT, ZERO_RECT};
use util::memory::SizeOf;
use util::range::Range;
use util::smallvec::{SmallVec, SmallVec8};
use std::fmt;
@ -198,6 +199,17 @@ impl DisplayList {
}
}
impl SizeOf for DisplayList {
fn size_of_excluding_self(&self) -> usize {
self.background_and_borders.size_of_excluding_self() +
self.block_backgrounds_and_borders.size_of_excluding_self() +
self.floats.size_of_excluding_self() +
self.content.size_of_excluding_self() +
self.outlines.size_of_excluding_self() +
self.children.size_of_excluding_self()
}
}
/// Represents one CSS stacking context, which may or may not have a hardware layer.
pub struct StackingContext {
/// The display items that make up this stacking context.
@ -501,6 +513,14 @@ impl StackingContext {
}
}
impl SizeOf for StackingContext {
fn size_of_excluding_self(&self) -> usize {
self.display_list.size_of_excluding_self()
// FIXME(njn): other fields may be measured later, esp. `layer`
}
}
/// Returns the stacking context in the given tree of stacking contexts with a specific layer ID.
pub fn find_stacking_context_with_layer_id(this: &Arc<StackingContext>, layer_id: LayerId)
-> Option<Arc<StackingContext>> {
@ -556,6 +576,13 @@ impl BaseDisplayItem {
}
}
impl SizeOf for BaseDisplayItem {
fn size_of_excluding_self(&self) -> usize {
self.metadata.size_of_excluding_self() +
self.clip.size_of_excluding_self()
}
}
/// A clipping region for a display item. Currently, this can describe rectangles, rounded
/// rectangles (for `border-radius`), or arbitrary intersections of the two. Arbitrary transforms
/// are not supported because those are handled by the higher-level `StackingContext` abstraction.
@ -681,6 +708,18 @@ impl ClippingRegion {
}
}
impl SizeOf for ClippingRegion {
fn size_of_excluding_self(&self) -> usize {
self.complex.size_of_excluding_self()
}
}
impl SizeOf for ComplexClippingRegion {
fn size_of_excluding_self(&self) -> usize {
0
}
}
/// Metadata attached to each display item. This is useful for performing auxiliary tasks with
/// the display list involving hit testing: finding the originating DOM node and determining the
/// cursor to use when the element is hovered over.
@ -712,6 +751,12 @@ impl DisplayItemMetadata {
}
}
impl SizeOf for DisplayItemMetadata {
fn size_of_excluding_self(&self) -> usize {
0
}
}
/// Paints a solid color.
#[derive(Clone)]
pub struct SolidColorDisplayItem {
@ -722,6 +767,12 @@ pub struct SolidColorDisplayItem {
pub color: Color,
}
impl SizeOf for SolidColorDisplayItem {
fn size_of_excluding_self(&self) -> usize {
self.base.size_of_excluding_self()
}
}
/// Paints text.
#[derive(Clone)]
pub struct TextDisplayItem {
@ -747,6 +798,13 @@ pub struct TextDisplayItem {
pub blur_radius: Au,
}
impl SizeOf for TextDisplayItem {
fn size_of_excluding_self(&self) -> usize {
self.base.size_of_excluding_self()
// We exclude `text_run` because it is non-owning.
}
}
#[derive(Clone, Eq, PartialEq)]
pub enum TextOrientation {
Upright,
@ -770,6 +828,13 @@ pub struct ImageDisplayItem {
pub image_rendering: image_rendering::T,
}
impl SizeOf for ImageDisplayItem {
fn size_of_excluding_self(&self) -> usize {
self.base.size_of_excluding_self()
// We exclude `image` here because it is non-owning.
}
}
/// Paints a gradient.
#[derive(Clone)]
pub struct GradientDisplayItem {
@ -786,6 +851,20 @@ pub struct GradientDisplayItem {
pub stops: Vec<GradientStop>,
}
impl SizeOf for GradientDisplayItem {
fn size_of_excluding_self(&self) -> usize {
use libc::c_void;
use util::memory::heap_size_of;
// We can't measure `stops` via Vec's SizeOf implementation because GradientStop isn't
// defined in this module, and we don't want to import GradientStop into util::memory where
// the SizeOf trait is defined. So we measure the elements directly.
self.base.size_of_excluding_self() +
heap_size_of(self.stops.as_ptr() as *const c_void)
}
}
/// Paints a border.
#[derive(Clone)]
pub struct BorderDisplayItem {
@ -807,6 +886,12 @@ pub struct BorderDisplayItem {
pub radius: BorderRadii<Au>,
}
impl SizeOf for BorderDisplayItem {
fn size_of_excluding_self(&self) -> usize {
self.base.size_of_excluding_self()
}
}
/// Information about the border radii.
///
/// TODO(pcwalton): Elliptical radii.
@ -851,6 +936,12 @@ pub struct LineDisplayItem {
pub style: border_style::T
}
impl SizeOf for LineDisplayItem {
fn size_of_excluding_self(&self) -> usize {
self.base.size_of_excluding_self()
}
}
/// Paints a box shadow per CSS-BACKGROUNDS.
#[derive(Clone)]
pub struct BoxShadowDisplayItem {
@ -876,6 +967,12 @@ pub struct BoxShadowDisplayItem {
pub clip_mode: BoxShadowClipMode,
}
impl SizeOf for BoxShadowDisplayItem {
fn size_of_excluding_self(&self) -> usize {
self.base.size_of_excluding_self()
}
}
/// How a box shadow should be clipped.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BoxShadowClipMode {
@ -1038,3 +1135,17 @@ impl fmt::Debug for DisplayItem {
}
}
impl SizeOf for DisplayItem {
fn size_of_excluding_self(&self) -> usize {
match *self {
SolidColorClass(ref item) => item.size_of_excluding_self(),
TextClass(ref item) => item.size_of_excluding_self(),
ImageClass(ref item) => item.size_of_excluding_self(),
BorderClass(ref item) => item.size_of_excluding_self(),
GradientClass(ref item) => item.size_of_excluding_self(),
LineClass(ref item) => item.size_of_excluding_self(),
BoxShadowClass(ref item) => item.size_of_excluding_self(),
}
}
}