Add a kind field to memory reports.

This is used for two memory reporting improvements.

- It's used to distinguish "explicit" memory reports from others. This
  mirrors the same categorization that is used in Firefox, and gives a single
  tree that's the best place to look. It replaces the "pages" tree which
  was always intended to be a temporary stand-in for "explicit".

- It's used to computed "heap-unclassified" values for both the jemalloc
  and system heaps, both of which are placed into the "explicit" tree.

Example output:
```
|  114.99 MiB -- explicit
|      52.34 MiB -- jemalloc-heap-unclassified
|      46.14 MiB -- system-heap-unclassified
|      14.95 MiB -- url(file:///home/njn/moz/servo2/../servo-static-suite/wikipe
dia/Guardians%20of%20the%20Galaxy%20(film)%20-%20Wikipedia,%20the%20free%20encyc
lopedia.html)
|          7.32 MiB -- js
|             3.07 MiB -- malloc-heap
|             3.00 MiB -- gc-heap
|                2.49 MiB -- used
|                0.34 MiB -- decommitted
|                0.09 MiB -- unused
|                0.09 MiB -- admin
|             1.25 MiB -- non-heap
|          1.36 MiB -- layout-worker-3-local-context
|          1.34 MiB -- layout-worker-0-local-context
|          1.24 MiB -- layout-worker-1-local-context
|          1.24 MiB -- layout-worker-4-local-context
|          1.16 MiB -- layout-worker-2-local-context
|          0.89 MiB -- layout-worker-5-local-context
|          0.38 MiB -- layout-task
|             0.31 MiB -- display-list
|             0.07 MiB -- local-context
|       1.56 MiB -- compositor-task
|          0.78 MiB -- surface-map
|          0.78 MiB -- layer-tree
```
The heap-unclassified values dominate the "explicit" tree because reporter
coverage is still quite poor.
This commit is contained in:
Nicholas Nethercote 2015-06-12 05:59:02 -07:00
parent b90fd5931d
commit 187068e2ae
5 changed files with 161 additions and 25 deletions

View file

@ -6,7 +6,8 @@
use ipc_channel::ipc::{self, IpcReceiver};
use ipc_channel::router::ROUTER;
use profile_traits::mem::{ProfilerChan, ProfilerMsg, Reporter, ReporterRequest, ReportsChan};
use profile_traits::mem::{ProfilerChan, ProfilerMsg, Reporter, ReporterRequest, ReportKind};
use profile_traits::mem::ReportsChan;
use std::borrow::ToOwned;
use std::cmp::Ordering;
use std::collections::HashMap;
@ -21,6 +22,9 @@ pub struct Profiler {
reporters: HashMap<String, Reporter>,
}
const JEMALLOC_HEAP_ALLOCATED_STR: &'static str = "jemalloc-heap-allocated";
const SYSTEM_HEAP_ALLOCATED_STR: &'static str = "system-heap-allocated";
impl Profiler {
pub fn create(period: Option<f64>) -> ProfilerChan {
let (chan, port) = ipc::channel().unwrap();
@ -122,16 +126,72 @@ impl Profiler {
// each reporter once we have enough of them.
//
// If anything goes wrong with a reporter, we just skip it.
//
// We also track the total memory reported on the jemalloc heap and the system heap, and
// use that to compute the special "jemalloc-heap-unclassified" and
// "system-heap-unclassified" values.
let mut forest = ReportsForest::new();
let mut jemalloc_heap_reported_size = 0;
let mut system_heap_reported_size = 0;
let mut jemalloc_heap_allocated_size: Option<usize> = None;
let mut system_heap_allocated_size: Option<usize> = None;
for reporter in self.reporters.values() {
let (chan, port) = ipc::channel().unwrap();
reporter.collect_reports(ReportsChan(chan));
if let Ok(reports) = port.recv() {
for report in reports.iter() {
if let Ok(mut reports) = port.recv() {
for report in reports.iter_mut() {
// Add "explicit" to the start of the path, when appropriate.
match report.kind {
ReportKind::ExplicitJemallocHeapSize |
ReportKind::ExplicitSystemHeapSize |
ReportKind::ExplicitNonHeapSize |
ReportKind::ExplicitUnknownLocationSize =>
report.path.insert(0, String::from("explicit")),
ReportKind::NonExplicitSize => {},
}
// Update the reported fractions of the heaps, when appropriate.
match report.kind {
ReportKind::ExplicitJemallocHeapSize =>
jemalloc_heap_reported_size += report.size,
ReportKind::ExplicitSystemHeapSize =>
system_heap_reported_size += report.size,
_ => {},
}
// Record total size of the heaps, when we see them.
if report.path.len() == 1 {
if report.path[0] == JEMALLOC_HEAP_ALLOCATED_STR {
assert!(jemalloc_heap_allocated_size.is_none());
jemalloc_heap_allocated_size = Some(report.size);
} else if report.path[0] == SYSTEM_HEAP_ALLOCATED_STR {
assert!(system_heap_allocated_size.is_none());
system_heap_allocated_size = Some(report.size);
}
}
// Insert the report.
forest.insert(&report.path, report.size);
}
}
}
// Compute and insert the heap-unclassified values.
if let Some(jemalloc_heap_allocated_size) = jemalloc_heap_allocated_size {
forest.insert(&path!["explicit", "jemalloc-heap-unclassified"],
jemalloc_heap_allocated_size - jemalloc_heap_reported_size);
}
if let Some(system_heap_allocated_size) = system_heap_allocated_size {
forest.insert(&path!["explicit", "system-heap-unclassified"],
system_heap_allocated_size - system_heap_reported_size);
}
forest.print();
println!("|");
@ -301,11 +361,12 @@ impl ReportsForest {
mod system_reporter {
use libc::{c_char, c_int, c_void, size_t};
use profile_traits::mem::{Report, ReporterRequest};
use profile_traits::mem::{Report, ReporterRequest, ReportKind};
use std::borrow::ToOwned;
use std::ffi::CString;
use std::mem::size_of;
use std::ptr::null_mut;
use super::{JEMALLOC_HEAP_ALLOCATED_STR, SYSTEM_HEAP_ALLOCATED_STR};
#[cfg(target_os="macos")]
use task_info::task_basic_info::{virtual_size, resident_size};
@ -315,7 +376,11 @@ mod system_reporter {
{
let mut report = |path, size| {
if let Some(size) = size {
reports.push(Report { path: path, size: size });
reports.push(Report {
path: path,
kind: ReportKind::NonExplicitSize,
size: size,
});
}
};
@ -330,13 +395,13 @@ mod system_reporter {
// Total number of bytes allocated by the application on the system
// heap.
report(path!["system-heap-allocated"], get_system_heap_allocated());
report(path![SYSTEM_HEAP_ALLOCATED_STR], get_system_heap_allocated());
// The descriptions of the following jemalloc measurements are taken
// directly from the jemalloc documentation.
// "Total number of bytes allocated by the application."
report(path!["jemalloc-heap-allocated"], get_jemalloc_stat("stats.allocated"));
report(path![JEMALLOC_HEAP_ALLOCATED_STR], get_jemalloc_stat("stats.allocated"));
// "Total number of bytes in active pages allocated by the application.
// This is a multiple of the page size, and greater than or equal to