Skip to content

Commit

Permalink
Measure LocalLayoutContexts in LayoutTask and LayoutWorkers.
Browse files Browse the repository at this point in the history
The FreeType instances in layout workers are reasonably large and worth
measuring. The one in LayoutTask is smaller but it's easy to measure at the
same time. Sample output:
```
|    8.33 MiB -- pages
|       8.33 MiB -- url(file:///home/njn/moz/servo/../servo-static-suite/wikipedia/Guardians%20of%20the%20Galaxy%20(film)%20-%20Wikipedia,%20the%20free%20encyclopedia.html)
|          1.32 MiB -- layout-worker-0-local-context
|          1.31 MiB -- layout-worker-1-local-context
|          1.24 MiB -- layout-worker-3-local-context
|          1.17 MiB -- layout-worker-4-local-context
|          1.08 MiB -- layout-worker-2-local-context
|          1.06 MiB -- layout-worker-5-local-context
|          0.78 MiB -- paint-task
|             0.78 MiB -- buffer-map
|          0.38 MiB -- layout-task
|             0.30 MiB -- display-list
|             0.07 MiB -- local-context
```
This required adding a mechanism to WorkQueue to measure worker TLSes.
  • Loading branch information
nnethercote committed Jun 11, 2015
1 parent fdeebf8 commit 48a0725
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 3 deletions.
14 changes: 14 additions & 0 deletions components/layout/context.rs
Expand Up @@ -29,6 +29,7 @@ use std::sync::mpsc::{channel, Sender};
use style::selector_matching::Stylist;
use url::Url;
use util::geometry::Au;
use util::mem::HeapSizeOf;
use util::opts;

struct LocalLayoutContext {
Expand All @@ -37,8 +38,21 @@ struct LocalLayoutContext {
style_sharing_candidate_cache: RefCell<StyleSharingCandidateCache>,
}

impl HeapSizeOf for LocalLayoutContext {
// FIXME(njn): measure other fields eventually.
fn heap_size_of_children(&self) -> usize {
self.font_context.heap_size_of_children()
}
}

thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<LocalLayoutContext>>> = RefCell::new(None));

pub fn heap_size_of_local_context() -> usize {
LOCAL_CONTEXT_KEY.with(|r| {
r.borrow().clone().map_or(0, |context| context.heap_size_of_children())
})
}

fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext)
-> Rc<LocalLayoutContext> {
LOCAL_CONTEXT_KEY.with(|r| {
Expand Down
22 changes: 20 additions & 2 deletions components/layout/layout_task.rs
Expand Up @@ -9,7 +9,7 @@

use animation;
use construct::ConstructionResult;
use context::{SharedLayoutContext, SharedLayoutContextWrapper};
use context::{SharedLayoutContext, SharedLayoutContextWrapper, heap_size_of_local_context};
use css::node_style::StyledNode;
use data::{LayoutDataAccess, LayoutDataWrapper};
use display_list_builder::ToGfxColor;
Expand Down Expand Up @@ -575,10 +575,28 @@ impl LayoutTask {
let rw_data = self.lock_rw_data(possibly_locked_rw_data);
let stacking_context = rw_data.stacking_context.as_ref();
reports.push(Report {
path: path!["pages", format!("url({})", self.url), "display-list"],
path: path!["pages", format!("url({})", self.url), "layout-task", "display-list"],
size: stacking_context.map_or(0, |sc| sc.heap_size_of_children()),
});

// The LayoutTask has a context in TLS...
reports.push(Report {
path: path!["pages", format!("url({})", self.url), "layout-task", "local-context"],
size: heap_size_of_local_context(),
});

// ... as do each of the LayoutWorkers, if present.
if let Some(ref traversal) = rw_data.parallel_traversal {
let sizes = traversal.heap_size_of_tls(heap_size_of_local_context);
for (i, size) in sizes.iter().enumerate() {
reports.push(Report {
path: path!["pages", format!("url({})", self.url),
format!("layout-worker-{}-local-context", i)],
size: *size
});
}
}

reports_chan.send(reports);
}

Expand Down
2 changes: 1 addition & 1 deletion components/profile/mem.rs
Expand Up @@ -224,7 +224,7 @@ impl ReportsTree {
}

let mebi = 1024f64 * 1024f64;
let count_str = if self.count > 1 { format!(" {}", self.count) } else { "".to_owned() };
let count_str = if self.count > 1 { format!(" [{}]", self.count) } else { "".to_owned() };
println!("|{}{:8.2} MiB -- {}{}",
indent_str, (self.size as f64) / mebi, self.path_seg, count_str);

Expand Down
7 changes: 7 additions & 0 deletions components/util/mem.rs
Expand Up @@ -5,6 +5,7 @@
//! Data structure measurement.

use libc::{c_void, size_t};
use std::cell::RefCell;
use std::collections::LinkedList;
use std::mem::transmute;
use std::sync::Arc;
Expand Down Expand Up @@ -92,6 +93,12 @@ impl<T: HeapSizeOf> HeapSizeOf for Arc<T> {
}
}

impl<T: HeapSizeOf> HeapSizeOf for RefCell<T> {
fn heap_size_of_children(&self) -> usize {
self.borrow().heap_size_of_children()
}
}

impl<T: HeapSizeOf> HeapSizeOf for Vec<T> {
fn heap_size_of_children(&self) -> usize {
heap_size_of(self.as_ptr() as *const c_void) +
Expand Down
28 changes: 28 additions & 0 deletions components/util/workqueue.rs
Expand Up @@ -36,6 +36,8 @@ enum WorkerMsg<QueueData: 'static, WorkData: 'static> {
Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
/// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
Stop,
/// Tells the worker to measure the heap size of its TLS using the supplied function.
HeapSizeOfTLS(fn() -> usize),
/// Tells the worker thread to terminate.
Exit,
}
Expand All @@ -45,6 +47,7 @@ unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerMsg<QueueData,
/// Messages to the supervisor.
enum SupervisorMsg<QueueData: 'static, WorkData: 'static> {
Finished,
HeapSizeOfTLS(usize),
ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
}

Expand Down Expand Up @@ -90,6 +93,10 @@ impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
WorkerMsg::Stop => panic!("unexpected stop message"),
WorkerMsg::Exit => return,
WorkerMsg::HeapSizeOfTLS(f) => {
self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
continue;
}
};

let mut back_off_sleep = 0 as u32;
Expand Down Expand Up @@ -315,11 +322,32 @@ impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
for _ in 0..self.workers.len() {
match self.port.recv().unwrap() {
SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
SupervisorMsg::Finished => panic!("unexpected finished message!"),
}
}
}

/// Synchronously measure memory usage of any thread-local storage.
pub fn heap_size_of_tls(&self, f: fn() -> usize) -> Vec<usize> {
// Tell the workers to measure themselves.
for worker in self.workers.iter() {
worker.chan.send(WorkerMsg::HeapSizeOfTLS(f)).unwrap()
}

// Wait for the workers to finish measuring themselves.
let mut sizes = vec![];
for _ in 0..self.workers.len() {
match self.port.recv().unwrap() {
SupervisorMsg::HeapSizeOfTLS(size) => {
sizes.push(size);
}
_ => panic!("unexpected message!"),
}
}
sizes
}

pub fn shutdown(&mut self) {
for worker in self.workers.iter() {
worker.chan.send(WorkerMsg::Exit).unwrap()
Expand Down

0 comments on commit 48a0725

Please sign in to comment.