Skip to content

Commit

Permalink
profile: Integrate the time profiler with the macOS signpost
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pcwalton authored and KiChjang committed Oct 1, 2016
1 parent 8b26c3e commit cb11d85
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 45 deletions.
3 changes: 3 additions & 0 deletions components/profile_traits/Cargo.toml
Expand Up @@ -19,4 +19,7 @@ energy-monitor = {version = "0.2.0", optional = true}
plugins = {path = "../plugins"}
serde = "0.8"
serde_macros = "0.8"
signpost = {git = "https://github.com/pcwalton/signpost.git"}
time = "0.1.12"
util = {path = "../util"}

2 changes: 2 additions & 0 deletions components/profile_traits/lib.rs
Expand Up @@ -14,6 +14,8 @@

extern crate ipc_channel;
extern crate serde;
extern crate signpost;
extern crate util;

pub mod energy;
pub mod mem;
Expand Down
101 changes: 56 additions & 45 deletions components/profile_traits/time.rs
Expand Up @@ -7,6 +7,8 @@ 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 {
Expand Down Expand Up @@ -37,51 +39,51 @@ pub enum ProfilerMsg {
#[repr(u32)]
#[derive(PartialEq, Clone, Copy, PartialOrd, Eq, Ord, Deserialize, Serialize, Debug, Hash)]
pub enum ProfilerCategory {
Compositing,
LayoutPerform,
LayoutStyleRecalc,
LayoutTextShaping,
LayoutRestyleDamagePropagation,
LayoutNonIncrementalReset,
LayoutSelectorMatch,
LayoutTreeBuilder,
LayoutDamagePropagate,
LayoutGeneratedContent,
LayoutDisplayListSorting,
LayoutFloatPlacementSpeculation,
LayoutMain,
LayoutStoreOverflow,
LayoutParallelWarmup,
LayoutDispListBuild,
NetHTTPRequestResponse,
PaintingPerTile,
PaintingPrepBuff,
Painting,
ImageDecoding,
ImageSaving,
ScriptAttachLayout,
ScriptConstellationMsg,
ScriptDevtoolsMsg,
ScriptDocumentEvent,
ScriptDomEvent,
ScriptEvaluate,
ScriptEvent,
ScriptFileRead,
ScriptImageCacheMsg,
ScriptInputEvent,
ScriptNetworkEvent,
ScriptParseHTML,
ScriptPlannedNavigation,
ScriptResize,
ScriptSetScrollState,
ScriptSetViewport,
ScriptTimerEvent,
ScriptStylesheetLoad,
ScriptUpdateReplacedElement,
ScriptWebSocketEvent,
ScriptWorkerEvent,
ScriptServiceWorkerEvent,
ApplicationHeartbeat,
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)]
Expand All @@ -103,11 +105,20 @@ pub fn profile<T, F>(category: ProfilerCategory,
-> 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,
Expand Down
8 changes: 8 additions & 0 deletions components/servo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions components/util/opts.rs
Expand Up @@ -217,6 +217,10 @@ pub struct Opts {
// don't skip any backtraces on panic
pub full_backtraces: bool,

/// True to use OS native signposting facilities. This makes profiling events (script activity,
/// reflow, compositing, etc.) appear in Instruments.app on macOS.
pub signpost: bool,

/// Print the version and exit.
pub is_printing_version: bool,
}
Expand Down Expand Up @@ -322,6 +326,10 @@ pub struct DebugOptions {
/// useful when modifying the shaders, to ensure they all compile
/// after each change is made.
pub precache_shaders: bool,

/// True to use OS native signposting facilities. This makes profiling events (script activity,
/// reflow, compositing, etc.) appear in Instruments.app on macOS.
pub signpost: bool,
}


Expand Down Expand Up @@ -361,6 +369,7 @@ impl DebugOptions {
"msaa" => debug_options.use_msaa = true,
"full-backtraces" => debug_options.full_backtraces = true,
"precache-shaders" => debug_options.precache_shaders = true,
"signpost" => debug_options.signpost = true,
"" => {},
_ => return Err(option)
};
Expand Down Expand Up @@ -411,6 +420,7 @@ pub fn print_debug_usage(app: &str) -> ! {
print_option("full-backtraces", "Print full backtraces for all errors");
print_option("wr-debug", "Display webrender tile borders. Must be used with -w option.");
print_option("precache-shaders", "Compile all shaders during init. Must be used with -w option.");
print_option("signpost", "Emit native OS signposts for profile events (currently macOS only)");

println!("");

Expand Down Expand Up @@ -549,6 +559,7 @@ pub fn default_opts() -> Opts {
is_printing_version: false,
webrender_debug: false,
precache_shaders: false,
signpost: false,
}
}

Expand Down Expand Up @@ -860,6 +871,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
is_printing_version: is_printing_version,
webrender_debug: debug_options.webrender_debug,
precache_shaders: debug_options.precache_shaders,
signpost: debug_options.signpost,
};

set_defaults(opts);
Expand Down
108 changes: 108 additions & 0 deletions etc/patch-trace-template.py
@@ -0,0 +1,108 @@
#!/usr/bin/env python

# Copyright 2013 The Servo Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.

import re
import subprocess
import sys
from xml.etree import ElementTree
from xml.etree.ElementTree import Element

if len(sys.argv) < 3:
sys.stderr.write("""usage: patch-trace-template.py components/profile_traits/time.rs path/to/my.tracetemplate
`time.rs` is usually located in `components/profile_traits/time.rs`.
Trace templates are typically located in `~/Library/Application Support/Instruments/Templates`.
The supplied trace template must contain the "Points of Interest" instrument.
Output is written to standard output and should typically be piped to a new `.tracetemplate` file.
Example:
patch-trace-template.py \\
components/profile_traits/time.rs \\
~/Library/Application\\ Support/Instruments/Templates/MyTemplate.tracetemplate > \\
~/Library/Application\\ Support/Instruments/Templates/MyServoTemplate.tracetemplate
""")
sys.exit(0)

rust_source = open(sys.argv[1], 'r')
lines = iter(rust_source)
for line in lines:
if line.lstrip().startswith("pub enum ProfilerCategory"):
break

code_pairs = []
regex = re.compile(r"\s*(\w+)\s*=\s*([0-9]+|0x[a-fA-F0-9]+),?\s*$")
for line in lines:
if line.lstrip().startswith("}"):
break

match = regex.match(line)
if match is None:
continue
code_pairs.append((match.group(2), match.group(1)))

xml = subprocess.check_output(["plutil", "-convert", "xml1", "-o", "-", sys.argv[2]])
plist = ElementTree.ElementTree(ElementTree.fromstring(xml))

elems = iter(plist.findall("./dict/*"))
for elem in elems:
if elem.tag != 'key' or elem.text != '$objects':
continue
array = elems.next()
break

elems = iter(array.findall("./*"))
for elem in elems:
if elem.tag != 'string' or elem.text != 'kdebugIntervalRule':
continue
dictionary = elems.next()
break

elems = iter(dictionary.findall("./*"))
for elem in elems:
if elem.tag != 'key' or elem.text != 'NS.objects':
continue
objects_array = elems.next()
break

child_count = sum(1 for _ in iter(array.findall("./*")))

for code_pair in code_pairs:
number_index = child_count
integer = Element('integer')
integer.text = str(int(code_pair[0], 0))
array.append(integer)
child_count += 1

string_index = child_count
string = Element('string')
string.text = code_pair[1]
array.append(string)
child_count += 1

dictionary = Element('dict')
key = Element('key')
key.text = "CF$UID"
dictionary.append(key)
integer = Element('integer')
integer.text = str(number_index)
dictionary.append(integer)
objects_array.append(dictionary)

dictionary = Element('dict')
key = Element('key')
key.text = "CF$UID"
dictionary.append(key)
integer = Element('integer')
integer.text = str(string_index)
dictionary.append(integer)
objects_array.append(dictionary)

plist.write(sys.stdout, encoding='utf-8', xml_declaration=True)
8 changes: 8 additions & 0 deletions ports/cef/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cb11d85

Please sign in to comment.