Auto merge of #15458 - connorimes:hbs-0.4, r=emilio

Update heartbeats-simple dependencies for bug fixes

<!-- Please describe your changes on the following line: -->

Updates heartbeats-simple dependencies for some bug fixes in native code (primarily for Windows).
Now we create heartbeats as needed so we don't have to maintain a hardcoded list which keeps getting out of sync.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #15471 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [X] These changes do not require tests because it updates a dependency and performs some code maintenance.

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15458)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-02-22 09:05:37 -08:00 committed by GitHub
commit 2bfea912dc
2 changed files with 73 additions and 80 deletions

View file

@ -2,95 +2,55 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use heartbeats_simple::HeartbeatPow as Heartbeat; use heartbeats_simple::HeartbeatPow as Heartbeat;
use heartbeats_simple::HeartbeatPowContext as HeartbeatContext;
use profile_traits::time::ProfilerCategory; use profile_traits::time::ProfilerCategory;
use self::synchronized_heartbeat::{heartbeat_window_callback, lock_and_work};
use servo_config::opts; use servo_config::opts;
use std::collections::HashMap; use std::collections::HashMap;
use std::env::var_os; use std::env::var_os;
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::File;
use std::mem;
use std::path::Path; use std::path::Path;
static mut HBS: Option<*mut HashMap<ProfilerCategory, Heartbeat>> = None;
/// Initialize heartbeats /// Initialize heartbeats
pub fn init() { pub fn init() {
let mut hbs: HashMap<ProfilerCategory, Heartbeat> = HashMap::new(); lock_and_work(|hbs_opt|
maybe_create_heartbeat(&mut hbs, ProfilerCategory::Compositing); if hbs_opt.is_none() {
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutPerform); let mut hbs: Box<HashMap<ProfilerCategory, Heartbeat>> = Box::new(HashMap::new());
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutStyleRecalc); maybe_create_heartbeat(&mut hbs, ProfilerCategory::ApplicationHeartbeat);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutTextShaping); *hbs_opt = Some(Box::into_raw(hbs))
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::LayoutDisplayListSorting);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutFloatPlacementSpeculation);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutMain);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutStoreOverflow);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutParallelWarmup);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::LayoutDispListBuild);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::NetHTTPRequestResponse);
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);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ImageSaving);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptAttachLayout);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptConstellationMsg);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptDevtoolsMsg);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptDocumentEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptDomEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptEvaluate);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptFileRead);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptImageCacheMsg);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptInputEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptNetworkEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptParseHTML);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptPlannedNavigation);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptResize);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptSetScrollState);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptSetViewport);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptTimerEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptStylesheetLoad);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptUpdateReplacedElement);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptWebSocketEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptWorkerEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptServiceWorkerEvent);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ScriptParseXML);
maybe_create_heartbeat(&mut hbs, ProfilerCategory::ApplicationHeartbeat);
unsafe {
HBS = Some(mem::transmute(Box::new(hbs)));
}
} }
/// Log regmaining buffer data and cleanup heartbeats /// Log regmaining buffer data and cleanup heartbeats
pub fn cleanup() { pub fn cleanup() {
unsafe { let hbs_opt_box: Option<Box<HashMap<ProfilerCategory, Heartbeat>>> = lock_and_work(|hbs_opt|
if let Some(hbs) = HBS { hbs_opt.take().map(|hbs_ptr|
let mut h: Box<HashMap<ProfilerCategory, Heartbeat>> = mem::transmute(hbs); unsafe {
for (_, mut v) in h.iter_mut() { Box::from_raw(hbs_ptr)
// log any remaining heartbeat records before dropping
log_heartbeat_records(v);
} }
h.clear(); )
);
if let Some(mut hbs) = hbs_opt_box {
for (_, mut v) in hbs.iter_mut() {
// log any remaining heartbeat records before dropping
log_heartbeat_records(v);
} }
HBS = None; hbs.clear();
} }
} }
/// Check if a heartbeat exists for the given category /// Check if a heartbeat exists for the given category
pub fn is_heartbeat_enabled(category: &ProfilerCategory) -> bool { pub fn is_heartbeat_enabled(category: &ProfilerCategory) -> bool {
unsafe { let is_enabled = lock_and_work(|hbs_opt|
HBS.map_or(false, |m| (*m).contains_key(category)) hbs_opt.map_or(false, |hbs_ptr|
} unsafe {
(*hbs_ptr).contains_key(category)
}
)
);
is_enabled || is_create_heartbeat(category)
} }
/// Issue a heartbeat (if one exists) for the given category /// Issue a heartbeat (if one exists) for the given category
@ -99,13 +59,18 @@ pub fn maybe_heartbeat(category: &ProfilerCategory,
end_time: u64, end_time: u64,
start_energy: u64, start_energy: u64,
end_energy: u64) { end_energy: u64) {
unsafe { lock_and_work(|hbs_opt|
if let Some(map) = HBS { if let Some(hbs_ptr) = *hbs_opt {
if let Some(mut h) = (*map).get_mut(category) { unsafe {
(*h).heartbeat(0, 1, start_time, end_time, start_energy, end_energy); if !(*hbs_ptr).contains_key(category) {
maybe_create_heartbeat(&mut (*hbs_ptr), category.clone());
}
if let Some(mut h) = (*hbs_ptr).get_mut(category) {
(*h).heartbeat(0, 1, start_time, end_time, start_energy, end_energy);
}
} }
} }
} );
} }
// TODO(cimes): Android doesn't really do environment variables. Need a better way to configure dynamically. // TODO(cimes): Android doesn't really do environment variables. Need a better way to configure dynamically.
@ -172,14 +137,39 @@ fn log_heartbeat_records(hb: &mut Heartbeat) {
} }
} }
/// Callback function used to log the window buffer. mod synchronized_heartbeat {
/// When this is called from native C, the heartbeat is safely locked use heartbeats_simple::HeartbeatPow as Heartbeat;
extern fn heartbeat_window_callback(hb: *const HeartbeatContext) { use heartbeats_simple::HeartbeatPowContext as HeartbeatContext;
unsafe { use profile_traits::time::ProfilerCategory;
if let Some(map) = HBS { use std::collections::HashMap;
for (_, v) in (*map).iter_mut() { use std::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering};
if &v.hb as *const HeartbeatContext == hb { use super::log_heartbeat_records;
log_heartbeat_records(v);
static mut HBS: Option<*mut HashMap<ProfilerCategory, Heartbeat>> = None;
// unfortunately can't encompass the actual hashmap in a Mutex (Heartbeat isn't Send/Sync), so we'll use a spinlock
static HBS_SPINLOCK: AtomicBool = ATOMIC_BOOL_INIT;
pub fn lock_and_work<F, R>(work: F) -> R
where F: FnOnce(&mut Option<*mut HashMap<ProfilerCategory, Heartbeat>>) -> R {
while HBS_SPINLOCK.compare_and_swap(false, true, Ordering::SeqCst) {}
let result = unsafe {
work(&mut HBS)
};
HBS_SPINLOCK.store(false, Ordering::SeqCst);
result
}
/// Callback function used to log the window buffer.
/// When this is called from native C, the heartbeat is safely locked internally and the global lock is held.
/// If calling from this file, you must already hold the global lock!
pub extern fn heartbeat_window_callback(hb: *const HeartbeatContext) {
unsafe {
if let Some(hbs_ptr) = HBS {
for (_, v) in (*hbs_ptr).iter_mut() {
if &v.hb as *const HeartbeatContext == hb {
log_heartbeat_records(v);
}
} }
} }
} }

View file

@ -65,6 +65,9 @@ HEARTBEAT_PROFILER_CATEGORIES = [
("ScriptWorkerEvent", HEARTBEAT_DEFAULT_WINDOW_SIZE), ("ScriptWorkerEvent", HEARTBEAT_DEFAULT_WINDOW_SIZE),
("ScriptServiceWorkerEvent", HEARTBEAT_DEFAULT_WINDOW_SIZE), ("ScriptServiceWorkerEvent", HEARTBEAT_DEFAULT_WINDOW_SIZE),
("ScriptParseXML", HEARTBEAT_DEFAULT_WINDOW_SIZE), ("ScriptParseXML", HEARTBEAT_DEFAULT_WINDOW_SIZE),
("ScriptEnterFullscreen", HEARTBEAT_DEFAULT_WINDOW_SIZE),
("ScriptExitFullscreen", HEARTBEAT_DEFAULT_WINDOW_SIZE),
("ScriptWebVREvent", HEARTBEAT_DEFAULT_WINDOW_SIZE),
("ApplicationHeartbeat", 100), ("ApplicationHeartbeat", 100),
] ]
ENERGY_READER_BIN = "energymon-file-provider" ENERGY_READER_BIN = "energymon-file-provider"