diff --git a/components/profile_traits/Cargo.toml b/components/profile_traits/Cargo.toml index f4b3687fc08d..150760b2ad2a 100644 --- a/components/profile_traits/Cargo.toml +++ b/components/profile_traits/Cargo.toml @@ -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"} + diff --git a/components/profile_traits/lib.rs b/components/profile_traits/lib.rs index ed404df14584..78fab60a4fa7 100644 --- a/components/profile_traits/lib.rs +++ b/components/profile_traits/lib.rs @@ -14,6 +14,8 @@ extern crate ipc_channel; extern crate serde; +extern crate signpost; +extern crate util; pub mod energy; pub mod mem; diff --git a/components/profile_traits/time.rs b/components/profile_traits/time.rs index 5b969ecd8f7e..64664265a1ac 100644 --- a/components/profile_traits/time.rs +++ b/components/profile_traits/time.rs @@ -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 { @@ -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)] @@ -103,11 +105,20 @@ pub fn profile(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, diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 1f45d97091d7..99bcd25856ad 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1846,7 +1846,9 @@ dependencies = [ "plugins 0.0.1", "serde 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", + "signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "util 0.0.1", ] [[package]] @@ -2250,6 +2252,11 @@ name = "sig" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "signpost" +version = "0.1.0" +source = "git+https://github.com/pcwalton/signpost.git#636f31b996ebec3f9d98e4d3973423a5d779666e" + [[package]] name = "simd" version = "0.1.1" @@ -2967,6 +2974,7 @@ dependencies = [ "checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a" "checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d" "checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5" +"checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "" "checksum simd 0.1.1 (git+https://github.com/huonw/simd)" = "" "checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410" "checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2" diff --git a/components/util/opts.rs b/components/util/opts.rs index 659ead8b4c5a..8cc67c1d2179 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -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, } @@ -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, } @@ -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) }; @@ -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!(""); @@ -549,6 +559,7 @@ pub fn default_opts() -> Opts { is_printing_version: false, webrender_debug: false, precache_shaders: false, + signpost: false, } } @@ -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); diff --git a/etc/patch-trace-template.py b/etc/patch-trace-template.py new file mode 100755 index 000000000000..84400c8e02e5 --- /dev/null +++ b/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 or the MIT license +# , 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) diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index b397478fcba7..496a684cc4fd 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1697,7 +1697,9 @@ dependencies = [ "plugins 0.0.1", "serde 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", + "signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "util 0.0.1", ] [[package]] @@ -2133,6 +2135,11 @@ name = "sig" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "signpost" +version = "0.1.0" +source = "git+https://github.com/pcwalton/signpost.git#81803b4d09af51a3a1133a62ef8dbb3cf0595de9" + [[package]] name = "simd" version = "0.1.1" @@ -2821,6 +2828,7 @@ dependencies = [ "checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a" "checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d" "checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5" +"checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "" "checksum simd 0.1.1 (git+https://github.com/huonw/simd)" = "" "checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410" "checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2"