profile: Make the time and memory profilers run over IPC.

Uses the `Router` abstraction inside `ipc-channel` to avoid spawning new
threads.
This commit is contained in:
Patrick Walton 2015-07-14 18:28:57 -07:00
parent ed1b6a3513
commit f10c076180
19 changed files with 212 additions and 168 deletions

View file

@ -4,26 +4,26 @@
//! Memory profiling functions.
use profile_traits::mem::{ProfilerChan, ProfilerMsg, Reporter, ReportsChan};
use self::system_reporter::SystemReporter;
use ipc_channel::ipc::{self, IpcReceiver};
use ipc_channel::router::ROUTER;
use profile_traits::mem::{ProfilerChan, ProfilerMsg, Reporter, ReporterRequest, ReportsChan};
use std::borrow::ToOwned;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::thread::sleep_ms;
use std::sync::mpsc::{channel, Receiver};
use util::task::spawn_named;
pub struct Profiler {
/// The port through which messages are received.
pub port: Receiver<ProfilerMsg>,
pub port: IpcReceiver<ProfilerMsg>,
/// Registered memory reporters.
reporters: HashMap<String, Box<Reporter + Send>>,
reporters: HashMap<String, Reporter>,
}
impl Profiler {
pub fn create(period: Option<f64>) -> ProfilerChan {
let (chan, port) = channel();
let (chan, port) = ipc::channel().unwrap();
// Create the timer thread if a period was provided.
if let Some(period) = period {
@ -48,16 +48,21 @@ impl Profiler {
let mem_profiler_chan = ProfilerChan(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 SystemReporter;
mem_profiler_chan.send(ProfilerMsg::RegisterReporter("system".to_owned(), system_reporter));
// Register the system memory reporter, which will run on its 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_sender, system_reporter_receiver) = ipc::channel().unwrap();
ROUTER.add_route(system_reporter_receiver.to_opaque(), box |message| {
let request: ReporterRequest = message.to().unwrap();
system_reporter::collect_reports(request)
});
mem_profiler_chan.send(ProfilerMsg::RegisterReporter("system".to_owned(),
Reporter(system_reporter_sender)));
mem_profiler_chan
}
pub fn new(port: Receiver<ProfilerMsg>) -> Profiler {
pub fn new(port: IpcReceiver<ProfilerMsg>) -> Profiler {
Profiler {
port: port,
reporters: HashMap::new(),
@ -119,12 +124,11 @@ impl Profiler {
// If anything goes wrong with a reporter, we just skip it.
let mut forest = ReportsForest::new();
for reporter in self.reporters.values() {
let (chan, port) = channel();
if reporter.collect_reports(ReportsChan(chan)) {
if let Ok(reports) = port.recv() {
for report in reports.iter() {
forest.insert(&report.path, report.size);
}
let (chan, port) = ipc::channel().unwrap();
reporter.collect_reports(ReportsChan(chan));
if let Ok(reports) = port.recv() {
for report in reports.iter() {
forest.insert(&report.path, report.size);
}
}
}
@ -297,7 +301,7 @@ impl ReportsForest {
mod system_reporter {
use libc::{c_char, c_int, c_void, size_t};
use profile_traits::mem::{Report, Reporter, ReportsChan};
use profile_traits::mem::{Report, ReporterRequest};
use std::borrow::ToOwned;
use std::ffi::CString;
use std::mem::size_of;
@ -306,51 +310,46 @@ mod system_reporter {
use task_info::task_basic_info::{virtual_size, resident_size};
/// Collects global measurements from the OS and heap allocators.
pub struct SystemReporter;
impl Reporter for SystemReporter {
fn collect_reports(&self, reports_chan: ReportsChan) -> bool {
let mut reports = vec![];
{
let mut report = |path, size| {
if let Some(size) = size {
reports.push(Report { path: path, size: size });
}
};
// Virtual and physical memory usage, as reported by the OS.
report(path!["vsize"], get_vsize());
report(path!["resident"], get_resident());
// Memory segments, as reported by the OS.
for seg in get_resident_segments().iter() {
report(path!["resident-according-to-smaps", seg.0], Some(seg.1));
pub fn collect_reports(request: ReporterRequest) {
let mut reports = vec![];
{
let mut report = |path, size| {
if let Some(size) = size {
reports.push(Report { path: path, size: size });
}
};
// Total number of bytes allocated by the application on the system
// heap.
report(path!["system-heap-allocated"], get_system_heap_allocated());
// Virtual and physical memory usage, as reported by the OS.
report(path!["vsize"], get_vsize());
report(path!["resident"], get_resident());
// 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"));
// "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(path!["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(path!["jemalloc-heap-mapped"], get_jemalloc_stat("stats.mapped"));
// Memory segments, as reported by the OS.
for seg in get_resident_segments().iter() {
report(path!["resident-according-to-smaps", seg.0], Some(seg.1));
}
reports_chan.send(reports);
true
// Total number of bytes allocated by the application on the system
// heap.
report(path!["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(path!["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(path!["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(path!["jemalloc-heap-mapped"], get_jemalloc_stat("stats.mapped"));
}
request.reports_channel.send(reports);
}
#[cfg(target_os="linux")]