aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/layout_task.rs
diff options
context:
space:
mode:
authorNicholas Nethercote <nnethercote@mozilla.com>2015-03-10 21:01:05 -0700
committerNicholas Nethercote <nnethercote@mozilla.com>2015-03-16 18:12:26 -0700
commitece2711185cffa8ade21b0ab9538bc1be79cadb9 (patch)
tree5870d8186ce791809ad1afcf65886767ea871a6b /components/layout/layout_task.rs
parent5865d5f71776336d8f55dcb326d1fb24279bbf63 (diff)
downloadservo-ece2711185cffa8ade21b0ab9538bc1be79cadb9.tar.gz
servo-ece2711185cffa8ade21b0ab9538bc1be79cadb9.zip
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.
Diffstat (limited to 'components/layout/layout_task.rs')
-rw-r--r--components/layout/layout_task.rs54
1 files changed, 52 insertions, 2 deletions
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs
index 5d1ab5781f8..d8c09a18218 100644
--- a/components/layout/layout_task.rs
+++ b/components/layout/layout_task.rs
@@ -56,6 +56,8 @@ use net::resource_task::{ResourceTask, load_bytes_iter};
use util::cursor::Cursor;
use util::geometry::Au;
use util::logical_geometry::LogicalPoint;
+use util::memory::{MemoryProfilerChan, MemoryProfilerMsg, MemoryReport, MemoryReportsChan};
+use util::memory::{SizeOf};
use util::opts;
use util::smallvec::{SmallVec, SmallVec1, VecLike};
use util::task::spawn_named_with_send_on_failure;
@@ -117,6 +119,9 @@ pub struct LayoutTask {
/// The ID of the pipeline that we belong to.
pub id: PipelineId,
+ /// The URL of the pipeline that we belong to.
+ pub url: Url,
+
/// The port on which we receive messages from the script task.
pub port: Receiver<Msg>,
@@ -138,6 +143,12 @@ pub struct LayoutTask {
/// The channel on which messages can be sent to the time profiler.
pub time_profiler_chan: TimeProfilerChan,
+ /// The channel on which messages can be sent to the memory profiler.
+ pub memory_profiler_chan: MemoryProfilerChan,
+
+ /// The name used for the task's memory reporter.
+ pub memory_reporter_name: String,
+
/// The channel on which messages can be sent to the resource task.
pub resource_task: ResourceTask,
@@ -181,6 +192,7 @@ impl LayoutTaskFactory for LayoutTask {
/// Spawns a new layout task.
fn create(_phantom: Option<&mut LayoutTask>,
id: PipelineId,
+ url: Url,
chan: OpaqueScriptLayoutChannel,
pipeline_port: Receiver<LayoutControlMsg>,
constellation_chan: ConstellationChan,
@@ -191,6 +203,7 @@ impl LayoutTaskFactory for LayoutTask {
img_cache_task: ImageCacheTask,
font_cache_task: FontCacheTask,
time_profiler_chan: TimeProfilerChan,
+ memory_profiler_chan: MemoryProfilerChan,
shutdown_chan: Sender<()>) {
let ConstellationChan(con_chan) = constellation_chan.clone();
spawn_named_with_send_on_failure("LayoutTask", task_state::LAYOUT, move || {
@@ -199,6 +212,7 @@ impl LayoutTaskFactory for LayoutTask {
let layout =
LayoutTask::new(
id,
+ url,
chan.receiver(),
LayoutChan(sender),
pipeline_port,
@@ -208,7 +222,8 @@ impl LayoutTaskFactory for LayoutTask {
resource_task,
img_cache_task,
font_cache_task,
- time_profiler_chan);
+ time_profiler_chan,
+ memory_profiler_chan);
layout.start();
}
shutdown_chan.send(()).unwrap();
@@ -249,6 +264,7 @@ impl<'a> DerefMut for RWGuard<'a> {
impl LayoutTask {
/// Creates a new `LayoutTask` structure.
fn new(id: PipelineId,
+ url: Url,
port: Receiver<Msg>,
chan: LayoutChan,
pipeline_port: Receiver<LayoutControlMsg>,
@@ -258,7 +274,8 @@ impl LayoutTask {
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
font_cache_task: FontCacheTask,
- time_profiler_chan: TimeProfilerChan)
+ time_profiler_chan: TimeProfilerChan,
+ memory_profiler_chan: MemoryProfilerChan)
-> LayoutTask {
let local_image_cache =
Arc::new(Mutex::new(LocalImageCache::new(image_cache_task.clone())));
@@ -271,8 +288,15 @@ impl LayoutTask {
None
};
+ // Register this thread as a memory reporter, via its own channel.
+ let reporter = Box::new(chan.clone());
+ let reporter_name = format!("layout-reporter-{}", id.0);
+ memory_profiler_chan.send(MemoryProfilerMsg::RegisterMemoryReporter(reporter_name.clone(),
+ reporter));
+
LayoutTask {
id: id,
+ url: url,
port: port,
pipeline_port: pipeline_port,
chan: chan,
@@ -280,6 +304,8 @@ impl LayoutTask {
constellation_chan: constellation_chan.clone(),
paint_chan: paint_chan,
time_profiler_chan: time_profiler_chan,
+ memory_profiler_chan: memory_profiler_chan,
+ memory_reporter_name: reporter_name,
resource_task: resource_task,
image_cache_task: image_cache_task.clone(),
font_cache_task: font_cache_task,
@@ -423,6 +449,9 @@ impl LayoutTask {
self.handle_reap_layout_data(dead_layout_data)
}
},
+ Msg::CollectMemoryReports(reports_chan) => {
+ self.collect_memory_reports(reports_chan, possibly_locked_rw_data);
+ },
Msg::PrepareToExit(response_chan) => {
debug!("layout: PrepareToExitMsg received");
self.prepare_to_exit(response_chan, possibly_locked_rw_data);
@@ -438,6 +467,23 @@ impl LayoutTask {
true
}
+ fn collect_memory_reports<'a>(&'a self,
+ reports_chan: MemoryReportsChan,
+ possibly_locked_rw_data:
+ &mut Option<MutexGuard<'a, LayoutTaskData>>) {
+ let mut reports = vec![];
+
+ // FIXME(njn): Just measuring the display tree for now.
+ let rw_data = self.lock_rw_data(possibly_locked_rw_data);
+ let stacking_context = rw_data.stacking_context.as_ref();
+ reports.push(MemoryReport {
+ name: format!("display-list::{}", self.url),
+ size: stacking_context.map_or(0, |sc| sc.size_of_excluding_self() as u64),
+ });
+
+ reports_chan.send(reports);
+ }
+
/// Enters a quiescent state in which no new messages except for `layout_interface::Msg::ReapLayoutData` will be
/// processed until an `ExitNowMsg` is received. A pong is immediately sent on the given
/// response channel.
@@ -481,6 +527,10 @@ impl LayoutTask {
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
}
+ let unregister_msg =
+ MemoryProfilerMsg::UnregisterMemoryReporter(self.memory_reporter_name.clone());
+ self.memory_profiler_chan.send(unregister_msg);
+
self.paint_chan.send(PaintMsg::Exit(Some(response_chan), exit_type));
response_port.recv().unwrap()
}