aboutsummaryrefslogtreecommitdiffstats
path: root/components/profile/heartbeats.rs
diff options
context:
space:
mode:
authorConnor Imes <connor.k.imes@gmail.com>2015-08-12 13:16:11 -0500
committerConnor Imes <connor.k.imes@gmail.com>2015-08-22 07:45:20 +0800
commit054cbf2dcea18e6dd33c14fac70477b6602f18bf (patch)
treee60c9e0cb76837aee040f74a91203abe6c1b856c /components/profile/heartbeats.rs
parent19d466b06250f10169e88fc7f0b447c7f2f8209e (diff)
downloadservo-054cbf2dcea18e6dd33c14fac70477b6602f18bf.tar.gz
servo-054cbf2dcea18e6dd33c14fac70477b6602f18bf.zip
Integrate with simple Heartbeats
Diffstat (limited to 'components/profile/heartbeats.rs')
-rw-r--r--components/profile/heartbeats.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/components/profile/heartbeats.rs b/components/profile/heartbeats.rs
new file mode 100644
index 00000000000..0d7f9511d4c
--- /dev/null
+++ b/components/profile/heartbeats.rs
@@ -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);
+ }
+ }
+ }
+ }
+}