Integrate with simple Heartbeats

This commit is contained in:
Connor Imes 2015-08-12 13:16:11 -05:00
parent 19d466b062
commit 054cbf2dce
8 changed files with 224 additions and 6 deletions

View file

@ -13,6 +13,9 @@ path = "../profile_traits"
[dependencies.util]
path = "../util"
[dependencies.hbs-pow]
git = "https://github.com/libheartbeats/heartbeats-simple-rust.git"
[dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel"

View file

@ -0,0 +1,120 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use hbs_pow::HeartbeatPow as Heartbeat;
use hbs_pow::HeartbeatPowContext as HeartbeatContext;
use profile_traits::time::ProfilerCategory;
use std::collections::HashMap;
use std::env::var_os;
use std::error::Error;
use std::fs::File;
use std::mem;
static mut HBS: Option<*mut HashMap<ProfilerCategory, Heartbeat>> = None;
/// Initialize heartbeats
pub fn init() {
let mut hbs: HashMap<ProfilerCategory, Heartbeat> = HashMap::new();
maybe_create_heartbeat(&mut hbs, ProfilerCategory::Compositing);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutPerform);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutStyleRecalc);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutRestyleDamagePropagation);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutNonIncrementalReset);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutSelectorMatch);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutTreeBuilder);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutDamagePropagate);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutGeneratedContent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutMain);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutParallelWarmup);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutShaping);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutDispListBuild);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::PaintingPerTile);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::PaintingPrepBuff);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::Painting);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ImageDecoding);
unsafe {
HBS = Some(mem::transmute(Box::new(hbs)));
}
}
/// Log regmaining buffer data and cleanup heartbeats
pub fn cleanup() {
unsafe {
if let Some(hbs) = HBS {
let mut h: Box<HashMap<ProfilerCategory, Heartbeat>> = mem::transmute(hbs);
for (_, mut v) in h.iter_mut() {
// log any remaining heartbeat records before dropping
log_heartbeat_records(v);
}
h.clear();
}
HBS = None;
}
}
/// Issue a heartbeat (if one exists) for the given category
pub fn maybe_heartbeat(category: &ProfilerCategory,
start_time: u64,
end_time: u64,
start_energy: u64,
end_energy: u64) {
unsafe {
if let Some(map) = HBS {
if let Some(mut h) = (*map).get_mut(category) {
(*h).heartbeat(0, 1, start_time, end_time, start_energy, end_energy);
}
}
}
}
/// Create a heartbeat if the correct environment variable is set
fn maybe_create_heartbeat(hbs: &mut HashMap<ProfilerCategory, Heartbeat>,
category: ProfilerCategory) {
static WINDOW_SIZE_DEFAULT: usize = 20;
if let Some(_) = var_os(format!("SERVO_HEARTBEAT_ENABLE_{:?}", category)) {
// get optional log file
let logfile: Option<File> = var_os(format!("SERVO_HEARTBEAT_LOG_{:?}", category))
.and_then(|name| File::create(name).ok());
// get window size
let window_size: usize = match var_os(format!("SERVO_HEARTBEAT_WINDOW_{:?}", category)) {
Some(w) => match w.into_string() {
Ok(s) => s.parse::<usize>().unwrap_or(WINDOW_SIZE_DEFAULT),
_ => WINDOW_SIZE_DEFAULT,
},
None => WINDOW_SIZE_DEFAULT,
};
// create the heartbeat
match Heartbeat::new(window_size, Some(heartbeat_window_callback), logfile) {
Ok(hb) => {
debug!("Created heartbeat for {:?}", category);
hbs.insert(category, hb);
},
Err(e) => warn!("Failed to create heartbeat for {:?}: {}", category, e),
}
};
}
/// Log heartbeat records up to the buffer index
fn log_heartbeat_records(hb: &mut Heartbeat) {
match hb.log_to_buffer_index() {
Ok(_) => (),
Err(e) => warn!("Failed to write heartbeat log: {}", Error::description(&e)),
}
}
/// Callback function used to log the window buffer.
/// When this is called from native C, the heartbeat is safely locked
extern fn heartbeat_window_callback(hb: *const HeartbeatContext) {
unsafe {
if let Some(map) = HBS {
for (_, v) in (*map).iter_mut() {
if &v.hb as *const HeartbeatContext == hb {
log_heartbeat_records(v);
}
}
}
}
}

View file

@ -8,6 +8,7 @@
#[macro_use] extern crate log;
extern crate hbs_pow;
extern crate ipc_channel;
extern crate libc;
#[macro_use]
@ -21,3 +22,5 @@ extern crate util;
pub mod mem;
pub mod time;
mod heartbeats;

View file

@ -4,6 +4,7 @@
//! Timing functions.
use heartbeats;
use ipc_channel::ipc::{self, IpcReceiver};
use profile_traits::time::{ProfilerCategory, ProfilerChan, ProfilerMsg, TimerMetadata};
use std::borrow::ToOwned;
@ -124,6 +125,7 @@ impl Profiler {
});
}
}
heartbeats::init();
ProfilerChan(chan)
}
@ -161,13 +163,20 @@ impl Profiler {
fn handle_msg(&mut self, msg: ProfilerMsg) -> bool {
match msg.clone() {
ProfilerMsg::Time(k, t) => self.find_or_insert(k, t),
ProfilerMsg::Time(k, t) => {
heartbeats::maybe_heartbeat(&k.0, t.0, t.1, 0, 0);
let ms = (t.1 - t.0) as f64 / 1000000f64;
self.find_or_insert(k, ms);
},
ProfilerMsg::Print => match self.last_msg {
// only print if more data has arrived since the last printout
Some(ProfilerMsg::Time(..)) => self.print_buckets(),
_ => ()
},
ProfilerMsg::Exit => return false,
ProfilerMsg::Exit => {
heartbeats::cleanup();
return false;
},
};
self.last_msg = Some(msg);
true

View file

@ -29,7 +29,7 @@ impl ProfilerChan {
#[derive(Clone, Deserialize, Serialize)]
pub enum ProfilerMsg {
/// Normal message used for reporting time
Time((ProfilerCategory, Option<TimerMetadata>), f64),
Time((ProfilerCategory, Option<TimerMetadata>), (u64, u64)),
/// Message used to force print the profiling metrics
Print,
/// Tells the profiler to shut down.
@ -37,7 +37,7 @@ pub enum ProfilerMsg {
}
#[repr(u32)]
#[derive(PartialEq, Clone, PartialOrd, Eq, Ord, Deserialize, Serialize)]
#[derive(PartialEq, Clone, PartialOrd, Eq, Ord, Deserialize, Serialize, Debug, Hash)]
pub enum ProfilerCategory {
Compositing,
LayoutPerform,
@ -83,13 +83,12 @@ pub fn profile<T, F>(category: ProfilerCategory,
let start_time = precise_time_ns();
let val = callback();
let end_time = precise_time_ns();
let ms = (end_time - start_time) as f64 / 1000000f64;
let meta = meta.map(|(url, iframe, reflow_type)|
TimerMetadata {
url: url.serialize(),
iframe: iframe == TimerMetadataFrameType::IFrame,
incremental: reflow_type == TimerMetadataReflowType::Incremental,
});
profiler_chan.send(ProfilerMsg::Time((category, meta), ms));
profiler_chan.send(ProfilerMsg::Time((category, meta), (start_time, end_time)));
return val;
}

View file

@ -630,6 +630,33 @@ dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-common-sys"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-sys.git#4476aa6ad4e2dfded87251d6069d9e747a54d9d8"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-pow"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-rust.git#70ad49c810da3842e12eef2075d58552f1f6c707"
dependencies = [
"hbs-pow-sys 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-sys.git)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-pow-sys"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-sys.git#4476aa6ad4e2dfded87251d6069d9e747a54d9d8"
dependencies = [
"hbs-common-sys 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-sys.git)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heapsize"
version = "0.1.2"
@ -1136,6 +1163,7 @@ source = "git+https://github.com/servo/rust-png#a3569ca11ea54e5d6152ee80d7d39b27
name = "profile"
version = "0.0.1"
dependencies = [
"hbs-pow 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-rust.git)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",

28
ports/cef/Cargo.lock generated
View file

@ -622,6 +622,33 @@ dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-common-sys"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-sys.git#4476aa6ad4e2dfded87251d6069d9e747a54d9d8"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-pow"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-rust.git#70ad49c810da3842e12eef2075d58552f1f6c707"
dependencies = [
"hbs-pow-sys 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-sys.git)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-pow-sys"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-sys.git#4476aa6ad4e2dfded87251d6069d9e747a54d9d8"
dependencies = [
"hbs-common-sys 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-sys.git)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heapsize"
version = "0.1.2"
@ -1114,6 +1141,7 @@ source = "git+https://github.com/servo/rust-png#a3569ca11ea54e5d6152ee80d7d39b27
name = "profile"
version = "0.0.1"
dependencies = [
"hbs-pow 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-rust.git)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",

28
ports/gonk/Cargo.lock generated
View file

@ -554,6 +554,33 @@ dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-common-sys"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-sys.git#4476aa6ad4e2dfded87251d6069d9e747a54d9d8"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-pow"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-rust.git#70ad49c810da3842e12eef2075d58552f1f6c707"
dependencies = [
"hbs-pow-sys 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-sys.git)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hbs-pow-sys"
version = "0.1.0"
source = "git+https://github.com/libheartbeats/heartbeats-simple-sys.git#4476aa6ad4e2dfded87251d6069d9e747a54d9d8"
dependencies = [
"hbs-common-sys 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-sys.git)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heapsize"
version = "0.1.2"
@ -1020,6 +1047,7 @@ source = "git+https://github.com/servo/rust-png#a3569ca11ea54e5d6152ee80d7d39b27
name = "profile"
version = "0.0.1"
dependencies = [
"hbs-pow 0.1.0 (git+https://github.com/libheartbeats/heartbeats-simple-rust.git)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",