Report detailed RSS measurements from /proc/<pid>/smaps on Linux.

All anonymous segments are aggregated into a single measurement, as are
all segments smaller than 512 KiB.

Example output:

      142.89: resident-according-to-smaps
       97.84: - anonymous (rw-p)
       23.98: - /home/njn/moz/servo/components/servo/target/servo (r-xp)
        6.58: - [heap] (rw-p)
        5.36: - other
        3.51: - /usr/lib/x86_64-linux-gnu/dri/i965_dri.so (r-xp)
        1.33: - /lib/x86_64-linux-gnu/libc-2.19.so (r-xp)
        0.93: - /home/njn/moz/servo/components/servo/target/servo (r--p)
        0.76: - /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20 (r-xp)
        0.74: - /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0 (r-xp)
        0.50: - /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (r-xp)
        0.50: - /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1 (r-xp)
        0.45: - /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1.2.0 (r-xp)
        0.43: - /lib/x86_64-linux-gnu/libm-2.19.so (r-xp)
This commit is contained in:
Nicholas Nethercote 2015-02-09 23:00:27 -08:00
parent 121394a121
commit 34a384241a
6 changed files with 144 additions and 9 deletions

View file

@ -696,6 +696,11 @@ dependencies = [
"log 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "regex"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rustc-serialize" name = "rustc-serialize"
version = "0.2.12" version = "0.2.12"
@ -867,6 +872,7 @@ dependencies = [
"libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1", "plugins 0.0.1",
"rand 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)", "string_cache 0.0.0 (git+https://github.com/servo/string-cache)",

View file

@ -43,10 +43,11 @@ git = "https://github.com/servo/string-cache"
git = "https://github.com/Kimundi/lazy-static.rs" git = "https://github.com/Kimundi/lazy-static.rs"
[dependencies] [dependencies]
text_writer = "0.1.1"
url = "0.2.16"
time = "0.1.12"
bitflags = "*" bitflags = "*"
rand = "*"
rustc-serialize = "0.2"
libc = "*" libc = "*"
rand = "*"
regex = "0.1.14"
rustc-serialize = "0.2"
text_writer = "0.1.1"
time = "0.1.12"
url = "0.2.16"

View file

@ -32,6 +32,8 @@ extern crate layers;
extern crate libc; extern crate libc;
#[no_link] #[macro_use] extern crate cssparser; #[no_link] #[macro_use] extern crate cssparser;
extern crate rand; extern crate rand;
#[cfg(target_os="linux")]
extern crate regex;
extern crate "rustc-serialize" as rustc_serialize; extern crate "rustc-serialize" as rustc_serialize;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
extern crate task_info; extern crate task_info;

View file

@ -11,8 +11,6 @@ use std::old_io::timer::sleep;
#[cfg(target_os="linux")] #[cfg(target_os="linux")]
use std::old_io::File; use std::old_io::File;
use std::mem::size_of; use std::mem::size_of;
#[cfg(target_os="linux")]
use std::env::page_size;
use std::ptr::null_mut; use std::ptr::null_mut;
use std::sync::mpsc::{Sender, channel, Receiver}; use std::sync::mpsc::{Sender, channel, Receiver};
use std::time::duration::Duration; use std::time::duration::Duration;
@ -126,6 +124,10 @@ impl MemoryProfiler {
MemoryProfiler::print_measurement("vsize", get_vsize()); MemoryProfiler::print_measurement("vsize", get_vsize());
MemoryProfiler::print_measurement("resident", get_resident()); 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 // Total number of bytes allocated by the application on the system
// heap. // heap.
MemoryProfiler::print_measurement("system-heap-allocated", MemoryProfiler::print_measurement("system-heap-allocated",
@ -244,8 +246,8 @@ fn get_proc_self_statm_field(field: uint) -> Option<u64> {
match f.read_to_string() { match f.read_to_string() {
Ok(contents) => { Ok(contents) => {
let s = option_try!(contents.as_slice().words().nth(field)); let s = option_try!(contents.as_slice().words().nth(field));
let npages: u64 = option_try!(s.parse().ok()); let npages = option_try!(s.parse::<u64>().ok());
Some(npages * (page_size() as u64)) Some(npages * (::std::env::page_size() as u64))
} }
Err(_) => None Err(_) => None
} }
@ -280,3 +282,115 @@ fn get_vsize() -> Option<u64> {
fn get_resident() -> Option<u64> { fn get_resident() -> Option<u64> {
None None
} }
#[cfg(target_os="linux")]
fn get_resident_segments() -> Vec<(String, u64)> {
use regex::Regex;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
// The first line of an entry in /proc/<pid>/smaps looks just like an entry
// in /proc/<pid>/maps:
//
// address perms offset dev inode pathname
// 02366000-025d8000 rw-p 00000000 00:00 0 [heap]
//
// Each of the following lines contains a key and a value, separated
// by ": ", where the key does not contain either of those characters.
// For example:
//
// Rss: 132 kB
let path = Path::new("/proc/self/smaps");
let mut f = ::std::old_io::BufferedReader::new(File::open(&path));
let seg_re = Regex::new(
r"^[:xdigit:]+-[:xdigit:]+ (....) [:xdigit:]+ [:xdigit:]+:[:xdigit:]+ \d+ +(.*)").unwrap();
let rss_re = Regex::new(r"^Rss: +(\d+) kB").unwrap();
// We record each segment's resident size.
let mut seg_map: HashMap<String, u64> = HashMap::new();
#[derive(PartialEq)]
enum LookingFor { Segment, Rss }
let mut looking_for = LookingFor::Segment;
let mut curr_seg_name = String::new();
// Parse the file.
for line in f.lines() {
let line = match line {
Ok(line) => line,
Err(_) => continue,
};
if looking_for == LookingFor::Segment {
// Look for a segment info line.
let cap = match seg_re.captures(line.as_slice()) {
Some(cap) => cap,
None => continue,
};
let perms = cap.at(1).unwrap();
let pathname = cap.at(2).unwrap();
// Construct the segment name from its pathname and permissions.
curr_seg_name.clear();
curr_seg_name.push_str("- ");
if pathname == "" || pathname.starts_with("[stack:") {
// Anonymous memory. Entries marked with "[stack:nnn]"
// look like thread stacks but they may include other
// anonymous mappings, so we can't trust them and just
// treat them as entirely anonymous.
curr_seg_name.push_str("anonymous");
} else {
curr_seg_name.push_str(pathname);
}
curr_seg_name.push_str(" (");
curr_seg_name.push_str(perms);
curr_seg_name.push_str(")");
looking_for = LookingFor::Rss;
} else {
// Look for an "Rss:" line.
let cap = match rss_re.captures(line.as_slice()) {
Some(cap) => cap,
None => continue,
};
let rss = cap.at(1).unwrap().parse::<u64>().unwrap() * 1024;
if rss > 0 {
// Aggregate small segments into "- other".
let seg_name = if rss < 512 * 1024 {
"- other".to_owned()
} else {
curr_seg_name.clone()
};
match seg_map.entry(seg_name) {
Entry::Vacant(entry) => { entry.insert(rss); },
Entry::Occupied(mut entry) => *entry.get_mut() += rss,
}
}
looking_for = LookingFor::Segment;
}
}
let mut segs: Vec<(String, u64)> = seg_map.into_iter().collect();
// Get the total and add it to the vector. Note that this total differs
// from the "resident" measurement obtained via /proc/<pid>/statm in
// get_resident(). It's unclear why this difference occurs; for some
// processes the measurements match, but for Servo they do not.
let total = segs.iter().fold(0u64, |total, &(_, size)| total + size);
segs.push(("resident-according-to-smaps".to_owned(), total));
// Sort by size; the total will be first.
segs.sort_by(|&(_, rss1), &(_, rss2)| rss2.cmp(&rss1));
segs
}
#[cfg(not(target_os="linux"))]
fn get_resident_segments() -> Vec<(String, u64)> {
vec![]
}

6
ports/cef/Cargo.lock generated
View file

@ -704,6 +704,11 @@ dependencies = [
"log 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "regex"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rustc-serialize" name = "rustc-serialize"
version = "0.2.12" version = "0.2.12"
@ -894,6 +899,7 @@ dependencies = [
"libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1", "plugins 0.0.1",
"rand 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)", "string_cache 0.0.0 (git+https://github.com/servo/string-cache)",

6
ports/gonk/Cargo.lock generated
View file

@ -616,6 +616,11 @@ dependencies = [
"log 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "regex"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rustc-serialize" name = "rustc-serialize"
version = "0.2.12" version = "0.2.12"
@ -797,6 +802,7 @@ dependencies = [
"libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1", "plugins 0.0.1",
"rand 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)", "string_cache 0.0.0 (git+https://github.com/servo/string-cache)",