mirror of
https://github.com/servo/servo.git
synced 2025-07-25 16:20:36 +01:00
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:
parent
121394a121
commit
34a384241a
6 changed files with 144 additions and 9 deletions
6
components/servo/Cargo.lock
generated
6
components/servo/Cargo.lock
generated
|
@ -696,6 +696,11 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.2.12"
|
||||
|
@ -867,6 +872,7 @@ dependencies = [
|
|||
"libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plugins 0.0.1",
|
||||
"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)",
|
||||
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||
|
|
|
@ -43,10 +43,11 @@ git = "https://github.com/servo/string-cache"
|
|||
git = "https://github.com/Kimundi/lazy-static.rs"
|
||||
|
||||
[dependencies]
|
||||
text_writer = "0.1.1"
|
||||
url = "0.2.16"
|
||||
time = "0.1.12"
|
||||
bitflags = "*"
|
||||
rand = "*"
|
||||
rustc-serialize = "0.2"
|
||||
libc = "*"
|
||||
rand = "*"
|
||||
regex = "0.1.14"
|
||||
rustc-serialize = "0.2"
|
||||
text_writer = "0.1.1"
|
||||
time = "0.1.12"
|
||||
url = "0.2.16"
|
||||
|
|
|
@ -32,6 +32,8 @@ extern crate layers;
|
|||
extern crate libc;
|
||||
#[no_link] #[macro_use] extern crate cssparser;
|
||||
extern crate rand;
|
||||
#[cfg(target_os="linux")]
|
||||
extern crate regex;
|
||||
extern crate "rustc-serialize" as rustc_serialize;
|
||||
#[cfg(target_os="macos")]
|
||||
extern crate task_info;
|
||||
|
|
|
@ -11,8 +11,6 @@ use std::old_io::timer::sleep;
|
|||
#[cfg(target_os="linux")]
|
||||
use std::old_io::File;
|
||||
use std::mem::size_of;
|
||||
#[cfg(target_os="linux")]
|
||||
use std::env::page_size;
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::mpsc::{Sender, channel, Receiver};
|
||||
use std::time::duration::Duration;
|
||||
|
@ -126,6 +124,10 @@ impl MemoryProfiler {
|
|||
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",
|
||||
|
@ -244,8 +246,8 @@ fn get_proc_self_statm_field(field: uint) -> Option<u64> {
|
|||
match f.read_to_string() {
|
||||
Ok(contents) => {
|
||||
let s = option_try!(contents.as_slice().words().nth(field));
|
||||
let npages: u64 = option_try!(s.parse().ok());
|
||||
Some(npages * (page_size() as u64))
|
||||
let npages = option_try!(s.parse::<u64>().ok());
|
||||
Some(npages * (::std::env::page_size() as u64))
|
||||
}
|
||||
Err(_) => None
|
||||
}
|
||||
|
@ -280,3 +282,115 @@ fn get_vsize() -> Option<u64> {
|
|||
fn get_resident() -> Option<u64> {
|
||||
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
6
ports/cef/Cargo.lock
generated
|
@ -704,6 +704,11 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.2.12"
|
||||
|
@ -894,6 +899,7 @@ dependencies = [
|
|||
"libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plugins 0.0.1",
|
||||
"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)",
|
||||
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||
|
|
6
ports/gonk/Cargo.lock
generated
6
ports/gonk/Cargo.lock
generated
|
@ -616,6 +616,11 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.2.12"
|
||||
|
@ -797,6 +802,7 @@ dependencies = [
|
|||
"libc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plugins 0.0.1",
|
||||
"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)",
|
||||
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue