mirror of
https://github.com/servo/servo.git
synced 2025-06-10 17:43:16 +00:00
Auto merge of #6334 - nnethercote:report-local-contexts, r=pcwalton
Passing a function that measures TLS to WorkQueue is a bit weird, but I can't see how else to measure that data. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6334) <!-- Reviewable:end -->
This commit is contained in:
commit
f03f584895
5 changed files with 70 additions and 3 deletions
|
@ -29,6 +29,7 @@ use std::sync::mpsc::{channel, Sender};
|
||||||
use style::selector_matching::Stylist;
|
use style::selector_matching::Stylist;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::geometry::Au;
|
use util::geometry::Au;
|
||||||
|
use util::mem::HeapSizeOf;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
|
|
||||||
struct LocalLayoutContext {
|
struct LocalLayoutContext {
|
||||||
|
@ -37,8 +38,21 @@ struct LocalLayoutContext {
|
||||||
style_sharing_candidate_cache: RefCell<StyleSharingCandidateCache>,
|
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));
|
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)
|
fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext)
|
||||||
-> Rc<LocalLayoutContext> {
|
-> Rc<LocalLayoutContext> {
|
||||||
LOCAL_CONTEXT_KEY.with(|r| {
|
LOCAL_CONTEXT_KEY.with(|r| {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
use animation;
|
use animation;
|
||||||
use construct::ConstructionResult;
|
use construct::ConstructionResult;
|
||||||
use context::{SharedLayoutContext, SharedLayoutContextWrapper};
|
use context::{SharedLayoutContext, SharedLayoutContextWrapper, heap_size_of_local_context};
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use data::{LayoutDataAccess, LayoutDataWrapper};
|
use data::{LayoutDataAccess, LayoutDataWrapper};
|
||||||
use display_list_builder::ToGfxColor;
|
use display_list_builder::ToGfxColor;
|
||||||
|
@ -575,10 +575,28 @@ impl LayoutTask {
|
||||||
let rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
let rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
let stacking_context = rw_data.stacking_context.as_ref();
|
let stacking_context = rw_data.stacking_context.as_ref();
|
||||||
reports.push(Report {
|
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()),
|
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);
|
reports_chan.send(reports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ impl ReportsTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mebi = 1024f64 * 1024f64;
|
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 -- {}{}",
|
println!("|{}{:8.2} MiB -- {}{}",
|
||||||
indent_str, (self.size as f64) / mebi, self.path_seg, count_str);
|
indent_str, (self.size as f64) / mebi, self.path_seg, count_str);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//! Data structure measurement.
|
//! Data structure measurement.
|
||||||
|
|
||||||
use libc::{c_void, size_t};
|
use libc::{c_void, size_t};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -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> {
|
impl<T: HeapSizeOf> HeapSizeOf for Vec<T> {
|
||||||
fn heap_size_of_children(&self) -> usize {
|
fn heap_size_of_children(&self) -> usize {
|
||||||
heap_size_of(self.as_ptr() as *const c_void) +
|
heap_size_of(self.as_ptr() as *const c_void) +
|
||||||
|
|
|
@ -36,6 +36,8 @@ enum WorkerMsg<QueueData: 'static, WorkData: 'static> {
|
||||||
Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
|
Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
|
||||||
/// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
|
/// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
|
||||||
Stop,
|
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.
|
/// Tells the worker thread to terminate.
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
@ -45,6 +47,7 @@ unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerMsg<QueueData,
|
||||||
/// Messages to the supervisor.
|
/// Messages to the supervisor.
|
||||||
enum SupervisorMsg<QueueData: 'static, WorkData: 'static> {
|
enum SupervisorMsg<QueueData: 'static, WorkData: 'static> {
|
||||||
Finished,
|
Finished,
|
||||||
|
HeapSizeOfTLS(usize),
|
||||||
ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
|
ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +105,10 @@ impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
|
||||||
WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
|
WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
|
||||||
WorkerMsg::Stop => panic!("unexpected stop message"),
|
WorkerMsg::Stop => panic!("unexpected stop message"),
|
||||||
WorkerMsg::Exit => return,
|
WorkerMsg::Exit => return,
|
||||||
|
WorkerMsg::HeapSizeOfTLS(f) => {
|
||||||
|
self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut back_off_sleep = 0 as u32;
|
let mut back_off_sleep = 0 as u32;
|
||||||
|
@ -335,11 +342,32 @@ impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
|
||||||
for _ in 0..self.workers.len() {
|
for _ in 0..self.workers.len() {
|
||||||
match self.port.recv().unwrap() {
|
match self.port.recv().unwrap() {
|
||||||
SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
|
SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
|
||||||
|
SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
|
||||||
SupervisorMsg::Finished => panic!("unexpected finished 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) {
|
pub fn shutdown(&mut self) {
|
||||||
for worker in self.workers.iter() {
|
for worker in self.workers.iter() {
|
||||||
worker.chan.send(WorkerMsg::Exit).unwrap()
|
worker.chan.send(WorkerMsg::Exit).unwrap()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue