Add timeline markers for HTTP requests, JS evaluation, and HTML parsing.

This commit is contained in:
Josh Matthews 2016-05-04 18:42:57 -04:00
parent 36df00ae96
commit 9e8cf19e51
19 changed files with 126 additions and 30 deletions

View file

@ -27,6 +27,7 @@ net_traits = {path = "../net_traits"}
openssl = "0.7.6"
openssl-verify = "0.1"
plugins = {path = "../plugins"}
profile_traits = {path = "../profile_traits"}
rustc-serialize = "0.3"
threadpool = "1.0"
time = "0.1.17"

View file

@ -31,6 +31,8 @@ use net_traits::response::HttpsState;
use net_traits::{CookieSource, IncludeSubdomains, LoadConsumer, LoadContext, LoadData};
use net_traits::{Metadata, NetworkError};
use openssl::ssl::error::{SslError, OpensslError};
use profile_traits::time::{ProfilerCategory, profile, ProfilerChan, TimerMetadata};
use profile_traits::time::{TimerMetadataReflowType, TimerMetadataFrameType};
use resource_thread::{CancellationListener, send_error, start_sending_sniffed_opt, AuthCache, AuthCacheEntry};
use std::borrow::ToOwned;
use std::boxed::FnBox;
@ -52,6 +54,7 @@ use uuid;
pub fn factory(user_agent: String,
http_state: HttpState,
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
profiler_chan: ProfilerChan,
connector: Arc<Pool<Connector>>)
-> Box<FnBox(LoadData,
LoadConsumer,
@ -59,6 +62,12 @@ pub fn factory(user_agent: String,
CancellationListener) + Send> {
box move |load_data: LoadData, senders, classifier, cancel_listener| {
spawn_named(format!("http_loader for {}", load_data.url), move || {
let metadata = TimerMetadata {
url: load_data.url.as_str().into(),
iframe: TimerMetadataFrameType::RootWindow,
incremental: TimerMetadataReflowType::FirstReflow,
};
profile(ProfilerCategory::NetHTTPRequestResponse, Some(metadata), profiler_chan, || {
load_for_consumer(load_data,
senders,
classifier,
@ -68,6 +77,7 @@ pub fn factory(user_agent: String,
cancel_listener,
user_agent)
})
})
}
}

View file

@ -31,6 +31,7 @@ extern crate msg;
extern crate net_traits;
extern crate openssl;
extern crate openssl_verify;
extern crate profile_traits;
extern crate rustc_serialize;
extern crate threadpool;
extern crate time;

View file

@ -23,6 +23,7 @@ use net_traits::ProgressMsg::Done;
use net_traits::{AsyncResponseTarget, Metadata, ProgressMsg, ResourceThread, ResponseAction};
use net_traits::{ControlMsg, CookieSource, LoadConsumer, LoadData, LoadResponse, ResourceId};
use net_traits::{NetworkError, WebSocketCommunicate, WebSocketConnectData};
use profile_traits::time::ProfilerChan;
use rustc_serialize::json;
use rustc_serialize::{Decodable, Encodable};
use std::borrow::ToOwned;
@ -150,13 +151,14 @@ fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata,
/// Create a ResourceThread
pub fn new_resource_thread(user_agent: String,
devtools_chan: Option<Sender<DevtoolsControlMsg>>) -> ResourceThread {
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
profiler_chan: ProfilerChan) -> ResourceThread {
let hsts_preload = HstsList::from_servo_preload();
let (setup_chan, setup_port) = ipc::channel().unwrap();
let setup_chan_clone = setup_chan.clone();
spawn_named("ResourceManager".to_owned(), move || {
let resource_manager = ResourceManager::new(
user_agent, hsts_preload, devtools_chan
user_agent, hsts_preload, devtools_chan, profiler_chan
);
let mut channel_manager = ResourceChannelManager {
@ -364,6 +366,7 @@ pub struct ResourceManager {
auth_cache: Arc<RwLock<AuthCache>>,
mime_classifier: Arc<MIMEClassifier>,
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
profiler_chan: ProfilerChan,
hsts_list: Arc<RwLock<HstsList>>,
connector: Arc<Pool<Connector>>,
cancel_load_map: HashMap<ResourceId, Sender<()>>,
@ -373,7 +376,8 @@ pub struct ResourceManager {
impl ResourceManager {
pub fn new(user_agent: String,
mut hsts_list: HstsList,
devtools_channel: Option<Sender<DevtoolsControlMsg>>) -> ResourceManager {
devtools_channel: Option<Sender<DevtoolsControlMsg>>,
profiler_chan: ProfilerChan) -> ResourceManager {
let mut auth_cache = AuthCache::new();
let mut cookie_jar = CookieStorage::new();
if let Some(ref profile_dir) = opts::get().profile_dir {
@ -387,6 +391,7 @@ impl ResourceManager {
auth_cache: Arc::new(RwLock::new(auth_cache)),
mime_classifier: Arc::new(MIMEClassifier::new()),
devtools_chan: devtools_channel,
profiler_chan: profiler_chan,
hsts_list: Arc::new(RwLock::new(hsts_list)),
connector: create_http_connector(),
cancel_load_map: HashMap::new(),
@ -445,6 +450,7 @@ impl ResourceManager {
http_loader::factory(self.user_agent.clone(),
http_state,
self.devtools_chan.clone(),
self.profiler_chan.clone(),
self.connector.clone())
},
"data" => from_factory(data_loader::factory),

View file

@ -122,6 +122,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::LayoutStoreOverflow => "Store Overflow",
ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
ProfilerCategory::LayoutDispListBuild => "Display List Construction",
ProfilerCategory::NetHTTPRequestResponse => "Network HTTP Request/Response",
ProfilerCategory::PaintingPerTile => "Painting Per Tile",
ProfilerCategory::PaintingPrepBuff => "Buffer Prep",
ProfilerCategory::Painting => "Painting",
@ -132,10 +133,12 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::ScriptDevtoolsMsg => "Script Devtools Msg",
ProfilerCategory::ScriptDocumentEvent => "Script Document Event",
ProfilerCategory::ScriptDomEvent => "Script Dom Event",
ProfilerCategory::ScriptEvaluate => "Script JS Evaluate",
ProfilerCategory::ScriptFileRead => "Script File Read",
ProfilerCategory::ScriptImageCacheMsg => "Script Image Cache Msg",
ProfilerCategory::ScriptInputEvent => "Script Input Event",
ProfilerCategory::ScriptNetworkEvent => "Script Network Event",
ProfilerCategory::ScriptParseHTML => "Script Parse HTML",
ProfilerCategory::ScriptPlannedNavigation => "Script Planned Navigation",
ProfilerCategory::ScriptResize => "Script Resize",
ProfilerCategory::ScriptEvent => "Script Event",

View file

@ -53,6 +53,7 @@ pub enum ProfilerCategory {
LayoutStoreOverflow,
LayoutParallelWarmup,
LayoutDispListBuild,
NetHTTPRequestResponse,
PaintingPerTile,
PaintingPrepBuff,
Painting,
@ -63,11 +64,13 @@ pub enum ProfilerCategory {
ScriptDevtoolsMsg,
ScriptDocumentEvent,
ScriptDomEvent,
ScriptEvaluate,
ScriptEvent,
ScriptFileRead,
ScriptImageCacheMsg,
ScriptInputEvent,
ScriptNetworkEvent,
ScriptParseHTML,
ScriptPlannedNavigation,
ScriptResize,
ScriptSetViewport,

View file

@ -20,7 +20,7 @@ use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue};
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
use msg::constellation_msg::{ConstellationChan, PipelineId};
use net_traits::ResourceThread;
use profile_traits::mem;
use profile_traits::{mem, time};
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort};
use script_thread::{MainThreadScriptChan, ScriptThread};
use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest};
@ -81,6 +81,14 @@ impl<'a> GlobalRef<'a> {
}
}
/// Get a `time::ProfilerChan` to send messages to the time profiler thread.
pub fn time_profiler_chan(&self) -> &time::ProfilerChan {
match *self {
GlobalRef::Window(window) => window.time_profiler_chan(),
GlobalRef::Worker(worker) => worker.time_profiler_chan(),
}
}
/// Get a `ConstellationChan` to send messages to the constellation channel when available.
pub fn constellation_chan(&self) -> &ConstellationChan<ConstellationMsg> {
match *self {

View file

@ -28,6 +28,8 @@ use msg::constellation_msg::{PipelineId, SubpageId};
use net_traits::{AsyncResponseListener, Metadata, NetworkError};
use network_listener::PreInvoke;
use parse::{TrustedParser, ParserRef, Parser};
use profile_traits::time::ProfilerCategory;
use profile_traits::time::{profile, TimerMetadata, TimerMetadataReflowType, TimerMetadataFrameType};
use script_thread::ScriptThread;
use std::cell::Cell;
use std::default::Default;
@ -315,6 +317,18 @@ impl ServoHTMLParser {
impl ServoHTMLParser {
pub fn parse_sync(&self) {
let metadata = TimerMetadata {
url: self.document.url().as_str().into(),
iframe: TimerMetadataFrameType::RootWindow,
incremental: TimerMetadataReflowType::FirstReflow,
};
profile(ProfilerCategory::ScriptParseHTML,
Some(metadata),
self.document.window().time_profiler_chan().clone(),
|| self.do_parse_sync())
}
fn do_parse_sync(&self) {
// This parser will continue to parse while there is either pending input or
// the parser remains unsuspended.
loop {

View file

@ -51,6 +51,8 @@ use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
use net_traits::storage_thread::{StorageThread, StorageType};
use num_traits::ToPrimitive;
use profile_traits::mem;
use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameType};
use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile};
use reporter::CSSErrorReporter;
use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
use script_runtime::{ScriptChan, ScriptPort};
@ -165,6 +167,10 @@ pub struct Window {
#[ignore_heap_size_of = "channels are hard"]
mem_profiler_chan: mem::ProfilerChan,
/// For sending messages to the memory profiler.
#[ignore_heap_size_of = "channels are hard"]
time_profiler_chan: ProfilerChan,
/// For providing instructions to an optional devtools server.
#[ignore_heap_size_of = "channels are hard"]
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
@ -841,6 +847,20 @@ impl<'a, T: Reflectable> ScriptHelpers for &'a T {
fn evaluate_script_on_global_with_result(self, code: &str, filename: &str,
rval: MutableHandleValue) {
let global = self.global();
let metadata = TimerMetadata {
url: if filename.is_empty() {
global.r().get_url().as_str().into()
} else {
filename.into()
},
iframe: TimerMetadataFrameType::RootWindow,
incremental: TimerMetadataReflowType::FirstReflow,
};
profile(
ProfilerCategory::ScriptEvaluate,
Some(metadata),
global.r().time_profiler_chan().clone(),
|| {
let cx = global.r().get_cx();
let globalhandle = global.r().reflector().get_jsobject();
let code: Vec<u16> = code.encode_utf16().collect();
@ -857,6 +877,8 @@ impl<'a, T: Reflectable> ScriptHelpers for &'a T {
}
}
}
)
}
}
impl Window {
@ -1259,6 +1281,10 @@ impl Window {
&self.mem_profiler_chan
}
pub fn time_profiler_chan(&self) -> &ProfilerChan {
&self.time_profiler_chan
}
pub fn devtools_chan(&self) -> Option<IpcSender<ScriptToDevtoolsControlMsg>> {
self.devtools_chan.clone()
}
@ -1424,6 +1450,7 @@ impl Window {
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
storage_thread: StorageThread,
mem_profiler_chan: mem::ProfilerChan,
time_profiler_chan: ProfilerChan,
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
constellation_chan: ConstellationChan<ConstellationMsg>,
control_chan: IpcSender<ConstellationControlMsg>,
@ -1460,6 +1487,7 @@ impl Window {
navigator: Default::default(),
image_cache_thread: image_cache_thread,
mem_profiler_chan: mem_profiler_chan,
time_profiler_chan: time_profiler_chan,
devtools_chan: devtools_chan,
browsing_context: Default::default(),
performance: Default::default(),

View file

@ -102,6 +102,7 @@ impl Worker {
let init = WorkerGlobalScopeInit {
resource_thread: resource_thread,
mem_profiler_chan: global.mem_profiler_chan().clone(),
time_profiler_chan: global.time_profiler_chan().clone(),
to_devtools_sender: global.devtools_chan(),
from_devtools_sender: optional_sender,
constellation_chan: constellation_chan,

View file

@ -23,7 +23,7 @@ use js::jsval::UndefinedValue;
use js::rust::Runtime;
use msg::constellation_msg::{ConstellationChan, PipelineId};
use net_traits::{LoadContext, ResourceThread, load_whole_resource};
use profile_traits::mem;
use profile_traits::{mem, time};
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort};
use script_traits::ScriptMsg as ConstellationMsg;
use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerEventRequest, TimerSource};
@ -45,6 +45,7 @@ pub enum WorkerGlobalScopeTypeId {
pub struct WorkerGlobalScopeInit {
pub resource_thread: ResourceThread,
pub mem_profiler_chan: mem::ProfilerChan,
pub time_profiler_chan: time::ProfilerChan,
pub to_devtools_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
pub from_devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
pub constellation_chan: ConstellationChan<ConstellationMsg>,
@ -72,6 +73,8 @@ pub struct WorkerGlobalScope {
timers: OneshotTimers,
#[ignore_heap_size_of = "Defined in std"]
mem_profiler_chan: mem::ProfilerChan,
#[ignore_heap_size_of = "Defined in std"]
time_profiler_chan: time::ProfilerChan,
#[ignore_heap_size_of = "Defined in ipc-channel"]
to_devtools_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
@ -118,6 +121,7 @@ impl WorkerGlobalScope {
crypto: Default::default(),
timers: OneshotTimers::new(timer_event_chan, init.scheduler_chan.clone()),
mem_profiler_chan: init.mem_profiler_chan,
time_profiler_chan: init.time_profiler_chan,
to_devtools_sender: init.to_devtools_sender,
from_devtools_sender: init.from_devtools_sender,
from_devtools_receiver: from_devtools_receiver,
@ -131,6 +135,10 @@ impl WorkerGlobalScope {
&self.mem_profiler_chan
}
pub fn time_profiler_chan(&self) -> &time::ProfilerChan {
&self.time_profiler_chan
}
pub fn devtools_chan(&self) -> Option<IpcSender<ScriptToDevtoolsControlMsg>> {
self.to_devtools_sender.clone()
}

View file

@ -1446,6 +1446,7 @@ impl ScriptThread {
self.bluetooth_thread.clone(),
self.storage_thread.clone(),
self.mem_profiler_chan.clone(),
self.time_profiler_chan.clone(),
self.devtools_chan.clone(),
self.constellation_chan.clone(),
self.control_chan.clone(),

View file

@ -1342,6 +1342,7 @@ dependencies = [
"openssl 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1",
"profile_traits 0.0.1",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"threadpool 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1379,6 +1380,7 @@ dependencies = [
"net 0.0.1",
"net_traits 0.0.1",
"plugins 0.0.1",
"profile_traits 0.0.1",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -210,7 +210,9 @@ fn create_constellation(opts: opts::Opts,
supports_clipboard: bool,
webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Sender<ConstellationMsg> {
let bluetooth_thread: IpcSender<BluetoothMethodMsg> = BluetoothThreadFactory::new();
let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone());
let resource_thread = new_resource_thread(opts.user_agent.clone(),
devtools_chan.clone(),
time_profiler_chan.clone());
let image_cache_thread = new_image_cache_thread(resource_thread.clone(),
webrender_api_sender.as_ref().map(|wr| wr.create_api()));
let font_cache_thread = FontCacheThread::new(resource_thread.clone(),

1
ports/cef/Cargo.lock generated
View file

@ -1248,6 +1248,7 @@ dependencies = [
"openssl 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1",
"profile_traits 0.0.1",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"threadpool 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",

1
ports/gonk/Cargo.lock generated
View file

@ -1240,6 +1240,7 @@ dependencies = [
"openssl 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1",
"profile_traits 0.0.1",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"threadpool 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -14,6 +14,7 @@ net_traits = {path = "../../../components/net_traits"}
util = {path = "../../../components/util"}
msg = {path = "../../../components/msg"}
plugins = {path = "../../../components/plugins"}
profile_traits = {path = "../../../components/profile_traits"}
devtools_traits = {path = "../../../components/devtools_traits"}
ipc-channel = {git = "https://github.com/servo/ipc-channel"}
cookie = "0.2"

View file

@ -13,6 +13,7 @@ extern crate ipc_channel;
extern crate msg;
extern crate net;
extern crate net_traits;
extern crate profile_traits;
extern crate time;
extern crate unicase;
extern crate url;

View file

@ -6,6 +6,7 @@ use ipc_channel::ipc;
use net::resource_thread::new_resource_thread;
use net_traits::hosts::{parse_hostsfile, host_replacement};
use net_traits::{ControlMsg, LoadData, LoadConsumer, LoadContext, NetworkError, ProgressMsg};
use profile_traits::time::ProfilerChan;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::net::IpAddr;
@ -18,13 +19,15 @@ fn ip(s: &str) -> IpAddr {
#[test]
fn test_exit() {
let resource_thread = new_resource_thread("".to_owned(), None);
let (tx, _rx) = ipc::channel().unwrap();
let resource_thread = new_resource_thread("".to_owned(), None, ProfilerChan(tx));
resource_thread.send(ControlMsg::Exit).unwrap();
}
#[test]
fn test_bad_scheme() {
let resource_thread = new_resource_thread("".to_owned(), None);
let (tx, _rx) = ipc::channel().unwrap();
let resource_thread = new_resource_thread("".to_owned(), None, ProfilerChan(tx));
let (start_chan, start) = ipc::channel().unwrap();
let url = Url::parse("bogus://whatever").unwrap();
resource_thread.send(ControlMsg::Load(LoadData::new(LoadContext::Browsing, url, None, None, None),
@ -200,7 +203,8 @@ fn test_cancelled_listener() {
}
});
let resource_thread = new_resource_thread("".to_owned(), None);
let (tx, _rx) = ipc::channel().unwrap();
let resource_thread = new_resource_thread("".to_owned(), None, ProfilerChan(tx));
let (sender, receiver) = ipc::channel().unwrap();
let (id_sender, id_receiver) = ipc::channel().unwrap();
let (sync_sender, sync_receiver) = ipc::channel().unwrap();