Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate with simple Heartbeats #7179

Merged
merged 1 commit into from Aug 22, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Integrate with simple Heartbeats

  • Loading branch information
connorimes committed Aug 21, 2015
commit 054cbf2dcea18e6dd33c14fac70477b6602f18bf
@@ -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"

@@ -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);
}
}
}
}
}
@@ -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;
@@ -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
@@ -29,15 +29,15 @@ 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.
Exit,
}

#[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;
}

Some generated files are not rendered by default. Learn more.

Some generated files are not rendered by default. Learn more.

Some generated files are not rendered by default. Learn more.

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.