From f306febd13bf407a2282b89cc129bc611054b88a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 17 Mar 2015 12:24:33 -0700 Subject: [PATCH] Put system memory measurements in a memory reporter. Currently the system memory measurements ("resident", "vsize", etc.) are not reported through the generic memory reporting mechanism, simply because they pre-date that mechanism. This changeset removes that special-casing. One consequence of this is that previously if a platform didn't implement one of the basic measurements, a '???' entry would be printed. Now nothing will be printed. This is no great loss and matches what Firefox does. Another consequence is that the order in which the measurements are printed is changed. I plan to fix this soon so that reports are sorted in a more sensible fashion. --- components/util/memory.rs | 113 +++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 51 deletions(-) diff --git a/components/util/memory.rs b/components/util/memory.rs index 11bec328f65..56bd91c3f88 100644 --- a/components/util/memory.rs +++ b/components/util/memory.rs @@ -265,7 +265,16 @@ impl MemoryProfiler { memory_profiler.start(); }); - MemoryProfilerChan(chan) + let memory_profiler_chan = MemoryProfilerChan(chan); + + // Register the system memory reporter, which will run on the memory profiler's own thread. + // It never needs to be unregistered, because as long as the memory profiler is running the + // system memory reporter can make measurements. + let system_reporter = Box::new(SystemMemoryReporter); + memory_profiler_chan.send(MemoryProfilerMsg::RegisterMemoryReporter("system".to_owned(), + system_reporter)); + + memory_profiler_chan } pub fn new(port: Receiver) -> MemoryProfiler { @@ -319,58 +328,11 @@ impl MemoryProfiler { } } - fn print_measurement(path: &str, nbytes: Option) { - match nbytes { - Some(nbytes) => { - let mebi = 1024f64 * 1024f64; - println!("{:12.2}: {}", (nbytes as f64) / mebi, path); - } - None => { - println!("{:>12}: {}", "???", path); - } - } - } - fn handle_print_msg(&self) { - println!("{:12}: {}", "_size (MiB)_", "_category_"); - // Collect global measurements from the OS and heap allocators. - - // Virtual and physical memory usage, as reported by the OS. - MemoryProfiler::print_measurement("vsize", get_vsize()); - MemoryProfiler::print_measurement("resident", get_resident()); - - for seg in get_resident_segments().iter() { - MemoryProfiler::print_measurement(seg.0.as_slice(), Some(seg.1)); - } - - // Total number of bytes allocated by the application on the system - // heap. - MemoryProfiler::print_measurement("system-heap-allocated", - 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." - MemoryProfiler::print_measurement("jemalloc-heap-allocated", - 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 - // |stats.allocated|." - MemoryProfiler::print_measurement("jemalloc-heap-active", - get_jemalloc_stat("stats.active")); - - // "Total number of bytes in chunks mapped on behalf of the application. - // This is a multiple of the chunk size, and is at least as large as - // |stats.active|. This does not include inactive chunks." - MemoryProfiler::print_measurement("jemalloc-heap-mapped", - get_jemalloc_stat("stats.mapped")); - // Collect reports from memory reporters. - + // // This serializes the report-gathering. It might be worth creating a new scoped thread for // each reporter once we have enough of them. // @@ -380,8 +342,8 @@ impl MemoryProfiler { if reporter.collect_reports(MemoryReportsChan(chan)) { if let Ok(reports) = port.recv() { for report in reports { - MemoryProfiler::print_measurement(report.name.as_slice(), - Some(report.size)); + let mebi = 1024f64 * 1024f64; + println!("{:12.2}: {}", (report.size as f64) / mebi, report.name); } } } @@ -391,6 +353,55 @@ impl MemoryProfiler { } } +/// Collects global measurements from the OS and heap allocators. +struct SystemMemoryReporter; + +impl MemoryReporter for SystemMemoryReporter { + fn collect_reports(&self, reports_chan: MemoryReportsChan) -> bool { + let mut reports = vec![]; + { + let mut report = |name: &str, size| { + if let Some(size) = size { + reports.push(MemoryReport { name: name.to_owned(), size: size }); + } + }; + + // Virtual and physical memory usage, as reported by the OS. + report("vsize", get_vsize()); + report("resident", get_resident()); + + // Memory segments, as reported by the OS. + for seg in get_resident_segments().iter() { + report(seg.0.as_slice(), Some(seg.1)); + } + + // Total number of bytes allocated by the application on the system + // heap. + report("system-heap-allocated", 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("jemalloc-heap-allocated", 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 + // |stats.allocated|." + report("jemalloc-heap-active", get_jemalloc_stat("stats.active")); + + // "Total number of bytes in chunks mapped on behalf of the application. + // This is a multiple of the chunk size, and is at least as large as + // |stats.active|. This does not include inactive chunks." + report("jemalloc-heap-mapped", get_jemalloc_stat("stats.mapped")); + } + reports_chan.send(reports); + + true + } +} + + #[cfg(target_os="linux")] extern { fn mallinfo() -> struct_mallinfo;