servo/components/profile_traits/time.rs
Patrick Walton cb11d85150 profile: Integrate the time profiler with the macOS signpost
infrastructure.

With this change, if you supply the `-Z signpost` flag, Instruments.app
can display Servo events overlaid with callstack data. Even better, you
can get call stack profiling for individual Servo events (one layout,
one network request, one style recalculation, etc.)

This adds a dependency on the `signpost` crate. On unsupported OS's,
this crate is an no-op.
2016-10-01 00:12:49 -07:00

142 lines
4.3 KiB
Rust

/* 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/. */
extern crate time as std_time;
use energy::read_energy_uj;
use ipc_channel::ipc::IpcSender;
use self::std_time::precise_time_ns;
use signpost;
use util::opts;
#[derive(PartialEq, Clone, PartialOrd, Eq, Ord, Debug, Deserialize, Serialize)]
pub struct TimerMetadata {
pub url: String,
pub iframe: TimerMetadataFrameType,
pub incremental: TimerMetadataReflowType,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct ProfilerChan(pub IpcSender<ProfilerMsg>);
impl ProfilerChan {
pub fn send(&self, msg: ProfilerMsg) {
self.0.send(msg).unwrap();
}
}
#[derive(Clone, Deserialize, Serialize)]
pub enum ProfilerMsg {
/// Normal message used for reporting time
Time((ProfilerCategory, Option<TimerMetadata>), (u64, u64), (u64, u64)),
/// Message used to force print the profiling metrics
Print,
/// Tells the profiler to shut down.
Exit(IpcSender<()>),
}
#[repr(u32)]
#[derive(PartialEq, Clone, Copy, PartialOrd, Eq, Ord, Deserialize, Serialize, Debug, Hash)]
pub enum ProfilerCategory {
Compositing = 0x00,
LayoutPerform = 0x10,
LayoutStyleRecalc = 0x11,
LayoutTextShaping = 0x12,
LayoutRestyleDamagePropagation = 0x13,
LayoutNonIncrementalReset = 0x14,
LayoutSelectorMatch = 0x15,
LayoutTreeBuilder = 0x16,
LayoutDamagePropagate = 0x17,
LayoutGeneratedContent = 0x18,
LayoutDisplayListSorting = 0x19,
LayoutFloatPlacementSpeculation = 0x1a,
LayoutMain = 0x1b,
LayoutStoreOverflow = 0x1c,
LayoutParallelWarmup = 0x1d,
LayoutDispListBuild = 0x1e,
NetHTTPRequestResponse = 0x30,
PaintingPerTile = 0x41,
PaintingPrepBuff = 0x42,
Painting = 0x43,
ImageDecoding = 0x50,
ImageSaving = 0x51,
ScriptAttachLayout = 0x60,
ScriptConstellationMsg = 0x61,
ScriptDevtoolsMsg = 0x62,
ScriptDocumentEvent = 0x63,
ScriptDomEvent = 0x64,
ScriptEvaluate = 0x65,
ScriptEvent = 0x66,
ScriptFileRead = 0x67,
ScriptImageCacheMsg = 0x68,
ScriptInputEvent = 0x69,
ScriptNetworkEvent = 0x6a,
ScriptParseHTML = 0x6b,
ScriptPlannedNavigation = 0x6c,
ScriptResize = 0x6d,
ScriptSetScrollState = 0x6e,
ScriptSetViewport = 0x6f,
ScriptTimerEvent = 0x70,
ScriptStylesheetLoad = 0x71,
ScriptUpdateReplacedElement = 0x72,
ScriptWebSocketEvent = 0x73,
ScriptWorkerEvent = 0x74,
ScriptServiceWorkerEvent = 0x75,
ApplicationHeartbeat = 0x90,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
pub enum TimerMetadataFrameType {
RootWindow,
IFrame,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
pub enum TimerMetadataReflowType {
Incremental,
FirstReflow,
}
pub fn profile<T, F>(category: ProfilerCategory,
meta: Option<TimerMetadata>,
profiler_chan: ProfilerChan,
callback: F)
-> T
where F: FnOnce() -> T
{
if opts::get().signpost {
signpost::start(category as u32, &[0, 0, 0, (category as usize) >> 4]);
}
let start_energy = read_energy_uj();
let start_time = precise_time_ns();
let val = callback();
let end_time = precise_time_ns();
let end_energy = read_energy_uj();
if opts::get().signpost {
signpost::end(category as u32, &[0, 0, 0, (category as usize) >> 4]);
}
send_profile_data(category,
meta,
profiler_chan,
start_time,
end_time,
start_energy,
end_energy);
val
}
pub fn send_profile_data(category: ProfilerCategory,
meta: Option<TimerMetadata>,
profiler_chan: ProfilerChan,
start_time: u64,
end_time: u64,
start_energy: u64,
end_energy: u64) {
profiler_chan.send(ProfilerMsg::Time((category, meta),
(start_time, end_time),
(start_energy, end_energy)));
}