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)",
|
"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)",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
6
ports/cef/Cargo.lock
generated
|
@ -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
6
ports/gonk/Cargo.lock
generated
|
@ -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)",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue