mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
auto merge of #4894 : nnethercote/servo/read-smaps, r=jdm
Here's example -m output after these changesets are applied: ``` _size (MiB)_: _category_ 2798.61: vsize 136.80: resident 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) 30.85: system-heap-allocated 4.91: jemalloc-heap-allocated 6.11: jemalloc-heap-active 120.00: jemalloc-heap-mapped ``` The `resident-according-to-smaps` line is new, as are all the indented lines beneath it. This is useful particularly because it shows how much memory is taken up by code, e.g. the line ending in `servo (r-xp)` shows that the `servo` executable's code alone takes up 24 MiB of physical memory.
This commit is contained in:
commit
eb7e86ac4e
6 changed files with 147 additions and 12 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;
|
||||
|
@ -111,21 +109,25 @@ impl MemoryProfiler {
|
|||
match nbytes {
|
||||
Some(nbytes) => {
|
||||
let mebi = 1024f64 * 1024f64;
|
||||
println!("{:24}: {:12.2}", path, (nbytes as f64) / mebi);
|
||||
println!("{:12.2}: {}", (nbytes as f64) / mebi, path);
|
||||
}
|
||||
None => {
|
||||
println!("{:24}: {:>12}", path, "???");
|
||||
println!("{:>12}: {}", "???", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_print_msg(&self) {
|
||||
println!("{:24}: {:12}", "_category_", "_size (MiB)_");
|
||||
println!("{:12}: {}", "_size (MiB)_", "_category_");
|
||||
|
||||
// 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",
|
||||
|
@ -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