servo: Merge #11239 - Add timeline markers for HTTP requests, JS evaluation, and HTML parsing (from jdm:time-profile); r=nox

Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data:
- [ ] `./mach build -d` does not report any errors (didn't try to compile past a rustc upgrade on airplane wifi)
- [X] `./mach test-tidy --faster` does not report any errors
- [X] These changes fix #11218 (github issue number if applicable).

Either:
- [ ] There are tests for these changes OR
- [X] These changes do not require tests because we don't have testing infrastructure for profiling.

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

Source-Repo: https://github.com/servo/servo
Source-Revision: 96a86bd952c4c0e41d6164fbd16244ea4420106a
This commit is contained in:
Josh Matthews 2016-05-18 06:07:10 -07:00
Родитель 4c6a748229
Коммит b10b472b1a
19 изменённых файлов: 126 добавлений и 30 удалений

Просмотреть файл

@ -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"

Просмотреть файл

@ -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,14 +62,21 @@ 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 || {
load_for_consumer(load_data,
senders,
classifier,
connector,
http_state,
devtools_chan,
cancel_listener,
user_agent)
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,
connector,
http_state,
devtools_chan,
cancel_listener,
user_agent)
})
})
}
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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),

Просмотреть файл

@ -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",

Просмотреть файл

@ -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,

Просмотреть файл

@ -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, PanicMsg, 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 {

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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>>,
@ -844,21 +850,37 @@ 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 cx = global.r().get_cx();
let globalhandle = global.r().reflector().get_jsobject();
let code: Vec<u16> = code.encode_utf16().collect();
let filename = CString::new(filename).unwrap();
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();
let filename = CString::new(filename).unwrap();
let _ac = JSAutoCompartment::new(cx, globalhandle.get());
let options = CompileOptionsWrapper::new(cx, filename.as_ptr(), 0);
unsafe {
if !Evaluate2(cx, options.ptr, code.as_ptr(),
code.len() as libc::size_t,
rval) {
debug!("error evaluating JS string");
report_pending_exception(cx, globalhandle.get());
let _ac = JSAutoCompartment::new(cx, globalhandle.get());
let options = CompileOptionsWrapper::new(cx, filename.as_ptr(), 0);
unsafe {
if !Evaluate2(cx, options.ptr, code.as_ptr(),
code.len() as libc::size_t,
rval) {
debug!("error evaluating JS string");
report_pending_exception(cx, globalhandle.get());
}
}
}
}
)
}
}
@ -1262,6 +1284,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()
}
@ -1431,6 +1457,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>,
@ -1468,6 +1495,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(),

Просмотреть файл

@ -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,

Просмотреть файл

@ -23,7 +23,7 @@ use js::jsval::UndefinedValue;
use js::rust::Runtime;
use msg::constellation_msg::{ConstellationChan, PanicMsg, 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>,
@ -73,6 +74,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>>,
@ -122,6 +125,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,
@ -136,6 +140,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()
}

Просмотреть файл

@ -1449,6 +1449,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(),

2
servo/components/servo/Cargo.lock сгенерированный
Просмотреть файл

@ -1368,6 +1368,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)",
@ -1405,6 +1406,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)",

Просмотреть файл

@ -211,7 +211,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
servo/ports/cef/Cargo.lock сгенерированный
Просмотреть файл

@ -1273,6 +1273,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
servo/ports/gonk/Cargo.lock сгенерированный
Просмотреть файл

@ -1265,6 +1265,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)",

Просмотреть файл

@ -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"

Просмотреть файл

@ -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;

Просмотреть файл

@ -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();