mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Firefox timeline integration #4957
This commit is contained in:
parent
1e45d025b3
commit
97714ec5ed
15 changed files with 761 additions and 14 deletions
|
@ -10,6 +10,7 @@ use std::cell::{Cell, RefCell};
|
||||||
use std::mem::{replace, transmute};
|
use std::mem::{replace, transmute};
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::raw::TraitObject;
|
use std::raw::TraitObject;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use rustc_serialize::json;
|
use rustc_serialize::json;
|
||||||
|
|
||||||
/// A common trait for all devtools actors that encompasses an immutable name
|
/// A common trait for all devtools actors that encompasses an immutable name
|
||||||
|
@ -77,7 +78,9 @@ impl Actor {
|
||||||
pub struct ActorRegistry {
|
pub struct ActorRegistry {
|
||||||
actors: HashMap<String, Box<Actor+Send>>,
|
actors: HashMap<String, Box<Actor+Send>>,
|
||||||
new_actors: RefCell<Vec<Box<Actor+Send>>>,
|
new_actors: RefCell<Vec<Box<Actor+Send>>>,
|
||||||
|
old_actors: RefCell<Vec<String>>,
|
||||||
script_actors: RefCell<HashMap<String, String>>,
|
script_actors: RefCell<HashMap<String, String>>,
|
||||||
|
shareable: Option<Arc<Mutex<ActorRegistry>>>,
|
||||||
next: Cell<u32>,
|
next: Cell<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +90,31 @@ impl ActorRegistry {
|
||||||
ActorRegistry {
|
ActorRegistry {
|
||||||
actors: HashMap::new(),
|
actors: HashMap::new(),
|
||||||
new_actors: RefCell::new(vec!()),
|
new_actors: RefCell::new(vec!()),
|
||||||
|
old_actors: RefCell::new(vec!()),
|
||||||
script_actors: RefCell::new(HashMap::new()),
|
script_actors: RefCell::new(HashMap::new()),
|
||||||
|
shareable: None,
|
||||||
next: Cell::new(0),
|
next: Cell::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creating shareable registry
|
||||||
|
pub fn create_shareable(self) -> Arc<Mutex<ActorRegistry>>{
|
||||||
|
if self.shareable.is_some() {
|
||||||
|
return self.shareable.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let shareable = Arc::new(Mutex::new(self));
|
||||||
|
let mut lock = shareable.lock();
|
||||||
|
let registry = lock.as_mut().unwrap();
|
||||||
|
registry.shareable = Some(shareable.clone());
|
||||||
|
shareable.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get shareable registry through threads
|
||||||
|
pub fn get_shareable(&self) -> Arc<Mutex<ActorRegistry>> {
|
||||||
|
self.shareable.as_ref().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register_script_actor(&self, script_id: String, actor: String) {
|
pub fn register_script_actor(&self, script_id: String, actor: String) {
|
||||||
println!("registering {} ({})", actor, script_id);
|
println!("registering {} ({})", actor, script_id);
|
||||||
let mut script_actors = self.script_actors.borrow_mut();
|
let mut script_actors = self.script_actors.borrow_mut();
|
||||||
|
@ -155,6 +178,7 @@ impl ActorRegistry {
|
||||||
stream: &mut TcpStream)
|
stream: &mut TcpStream)
|
||||||
-> Result<(), ()> {
|
-> Result<(), ()> {
|
||||||
let to = msg.get("to").unwrap().as_string().unwrap();
|
let to = msg.get("to").unwrap().as_string().unwrap();
|
||||||
|
|
||||||
match self.actors.get(&to.to_string()) {
|
match self.actors.get(&to.to_string()) {
|
||||||
None => println!("message received for unknown actor \"{}\"", to),
|
None => println!("message received for unknown actor \"{}\"", to),
|
||||||
Some(actor) => {
|
Some(actor) => {
|
||||||
|
@ -169,6 +193,20 @@ impl ActorRegistry {
|
||||||
for actor in new_actors.into_iter() {
|
for actor in new_actors.into_iter() {
|
||||||
self.actors.insert(actor.name().to_string(), actor);
|
self.actors.insert(actor.name().to_string(), actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let old_actors = replace(&mut *self.old_actors.borrow_mut(), vec!());
|
||||||
|
for name in old_actors.into_iter() {
|
||||||
|
self.drop_actor(name);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drop_actor(&mut self, name: String) {
|
||||||
|
self.actors.remove(&name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drop_actor_later(&self, name: String) {
|
||||||
|
let mut actors = self.old_actors.borrow_mut();
|
||||||
|
actors.push(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
88
components/devtools/actors/framerate.rs
Normal file
88
components/devtools/actors/framerate.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
use rustc_serialize::json;
|
||||||
|
use std::mem;
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use time::precise_time_ns;
|
||||||
|
|
||||||
|
use actor::{Actor, ActorRegistry};
|
||||||
|
|
||||||
|
pub struct FramerateActor {
|
||||||
|
name: String,
|
||||||
|
start_time: Option<u64>,
|
||||||
|
is_recording: bool,
|
||||||
|
ticks: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Actor for FramerateActor {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn handle_message(&self,
|
||||||
|
_registry: &ActorRegistry,
|
||||||
|
_msg_type: &str,
|
||||||
|
_msg: &json::Object,
|
||||||
|
_stream: &mut TcpStream) -> Result<bool, ()> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FramerateActor {
|
||||||
|
/// return name of actor
|
||||||
|
pub fn create(registry: &ActorRegistry) -> String {
|
||||||
|
let actor_name = registry.new_name("framerate");
|
||||||
|
let mut actor = FramerateActor {
|
||||||
|
name: actor_name.clone(),
|
||||||
|
start_time: None,
|
||||||
|
is_recording: false,
|
||||||
|
ticks: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
actor.start_recording();
|
||||||
|
registry.register_later(box actor);
|
||||||
|
actor_name
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback on request animation frame
|
||||||
|
pub fn on_refresh_driver_tick(&mut self) {
|
||||||
|
if !self.is_recording {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: Need implement requesting animation frame
|
||||||
|
// http://hg.mozilla.org/mozilla-central/file/0a46652bd992/dom/base/nsGlobalWindow.cpp#l5314
|
||||||
|
|
||||||
|
let start_time = self.start_time.as_ref().unwrap();
|
||||||
|
self.ticks.push(*start_time - precise_time_ns());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_pending_ticks(&mut self) -> Vec<u64> {
|
||||||
|
mem::replace(&mut self.ticks, Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_recording(&mut self) {
|
||||||
|
self.is_recording = true;
|
||||||
|
self.start_time = Some(precise_time_ns());
|
||||||
|
|
||||||
|
// TODO: Need implement requesting animation frame
|
||||||
|
// http://hg.mozilla.org/mozilla-central/file/0a46652bd992/dom/base/nsGlobalWindow.cpp#l5314
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_recording(&mut self) {
|
||||||
|
if !self.is_recording {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.is_recording = false;
|
||||||
|
self.start_time = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for FramerateActor {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop_recording();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,9 +15,9 @@ use collections::BTreeMap;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use rustc_serialize::json::{self, Json, ToJson};
|
use rustc_serialize::json::{self, Json, ToJson};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::mpsc::{channel, Sender};
|
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::num::Float;
|
use std::num::Float;
|
||||||
|
use std::sync::mpsc::{channel, Sender};
|
||||||
|
|
||||||
pub struct InspectorActor {
|
pub struct InspectorActor {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
67
components/devtools/actors/memory.rs
Normal file
67
components/devtools/actors/memory.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
use rustc_serialize::json;
|
||||||
|
use std::net::TcpStream;
|
||||||
|
|
||||||
|
use actor::{Actor, ActorRegistry};
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
pub struct TimelineMemoryReply {
|
||||||
|
jsObjectSize: u64,
|
||||||
|
jsStringSize: u64,
|
||||||
|
jsOtherSize: u64,
|
||||||
|
domSize: u64,
|
||||||
|
styleSize: u64,
|
||||||
|
otherSize: u64,
|
||||||
|
totalSize: u64,
|
||||||
|
jsMilliseconds: f64,
|
||||||
|
nonJSMilliseconds: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MemoryActor {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Actor for MemoryActor {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_message(&self,
|
||||||
|
_registry: &ActorRegistry,
|
||||||
|
_msg_type: &str,
|
||||||
|
_msg: &json::Object,
|
||||||
|
_stream: &mut TcpStream) -> Result<bool, ()> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryActor {
|
||||||
|
/// return name of actor
|
||||||
|
pub fn create(registry: &ActorRegistry) -> String {
|
||||||
|
let actor_name = registry.new_name("memory");
|
||||||
|
let actor = MemoryActor {
|
||||||
|
name: actor_name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
registry.register_later(box actor);
|
||||||
|
actor_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn measure(&self) -> TimelineMemoryReply {
|
||||||
|
//TODO:
|
||||||
|
TimelineMemoryReply {
|
||||||
|
jsObjectSize: 1,
|
||||||
|
jsStringSize: 1,
|
||||||
|
jsOtherSize: 1,
|
||||||
|
domSize: 1,
|
||||||
|
styleSize: 1,
|
||||||
|
otherSize: 1,
|
||||||
|
totalSize: 1,
|
||||||
|
jsMilliseconds: 1.1,
|
||||||
|
nonJSMilliseconds: 1.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,6 +60,7 @@ pub struct TabActorMsg {
|
||||||
outerWindowID: u32,
|
outerWindowID: u32,
|
||||||
consoleActor: String,
|
consoleActor: String,
|
||||||
inspectorActor: String,
|
inspectorActor: String,
|
||||||
|
timelineActor: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TabActor {
|
pub struct TabActor {
|
||||||
|
@ -68,6 +69,7 @@ pub struct TabActor {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub console: String,
|
pub console: String,
|
||||||
pub inspector: String,
|
pub inspector: String,
|
||||||
|
pub timeline: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actor for TabActor {
|
impl Actor for TabActor {
|
||||||
|
@ -143,6 +145,7 @@ impl TabActor {
|
||||||
outerWindowID: 0, //FIXME: this should probably be the pipeline id
|
outerWindowID: 0, //FIXME: this should probably be the pipeline id
|
||||||
consoleActor: self.console.clone(),
|
consoleActor: self.console.clone(),
|
||||||
inspectorActor: self.inspector.clone(),
|
inspectorActor: self.inspector.clone(),
|
||||||
|
timelineActor: self.timeline.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
352
components/devtools/actors/timeline.rs
Normal file
352
components/devtools/actors/timeline.rs
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
use core::iter::FromIterator;
|
||||||
|
use msg::constellation_msg::PipelineId;
|
||||||
|
use rustc_serialize::json;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use std::old_io::timer::sleep;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::duration::Duration;
|
||||||
|
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
|
||||||
|
use time::precise_time_ns;
|
||||||
|
|
||||||
|
use actor::{Actor, ActorRegistry};
|
||||||
|
use actors::memory::{MemoryActor, TimelineMemoryReply};
|
||||||
|
use actors::framerate::FramerateActor;
|
||||||
|
use devtools_traits::DevtoolScriptControlMsg;
|
||||||
|
use devtools_traits::DevtoolScriptControlMsg::{SetTimelineMarkers, DropTimelineMarkers};
|
||||||
|
use devtools_traits::{TimelineMarker, TracingMetadata, TimelineMarkerType};
|
||||||
|
use protocol::JsonPacketStream;
|
||||||
|
use util::task;
|
||||||
|
|
||||||
|
pub struct TimelineActor {
|
||||||
|
name: String,
|
||||||
|
script_sender: Sender<DevtoolScriptControlMsg>,
|
||||||
|
marker_types: Vec<TimelineMarkerType>,
|
||||||
|
pipeline: PipelineId,
|
||||||
|
is_recording: Arc<Mutex<bool>>,
|
||||||
|
stream: RefCell<Option<TcpStream>>,
|
||||||
|
|
||||||
|
framerate_actor: RefCell<Option<String>>,
|
||||||
|
memory_actor: RefCell<Option<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Emitter {
|
||||||
|
from: String,
|
||||||
|
stream: TcpStream,
|
||||||
|
markers: Vec<TimelineMarkerReply>,
|
||||||
|
registry: Arc<Mutex<ActorRegistry>>,
|
||||||
|
|
||||||
|
framerate_actor: Option<String>,
|
||||||
|
memory_actor: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
struct IsRecordingReply {
|
||||||
|
from: String,
|
||||||
|
value: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
struct StartReply {
|
||||||
|
from: String,
|
||||||
|
value: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
struct StopReply {
|
||||||
|
from: String,
|
||||||
|
value: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
struct TimelineMarkerReply {
|
||||||
|
name: String,
|
||||||
|
start: u64,
|
||||||
|
end: u64,
|
||||||
|
stack: Option<Vec<()>>,
|
||||||
|
endStack: Option<Vec<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
struct MarkersEmitterReply {
|
||||||
|
__type__: String,
|
||||||
|
markers: Vec<TimelineMarkerReply>,
|
||||||
|
from: String,
|
||||||
|
endTime: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
struct MemoryEmitterReply {
|
||||||
|
__type__: String,
|
||||||
|
from: String,
|
||||||
|
delta: u64,
|
||||||
|
measurement: TimelineMemoryReply,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RustcEncodable)]
|
||||||
|
struct FramerateEmitterReply {
|
||||||
|
__type__: String,
|
||||||
|
from: String,
|
||||||
|
delta: u64,
|
||||||
|
timestamps: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_TIMELINE_DATA_PULL_TIMEOUT: usize = 200; //ms
|
||||||
|
|
||||||
|
impl TimelineActor {
|
||||||
|
pub fn new(name: String,
|
||||||
|
pipeline: PipelineId,
|
||||||
|
script_sender: Sender<DevtoolScriptControlMsg>) -> TimelineActor {
|
||||||
|
|
||||||
|
let marker_types = vec!(TimelineMarkerType::Reflow,
|
||||||
|
TimelineMarkerType::DOMEvent);
|
||||||
|
|
||||||
|
TimelineActor {
|
||||||
|
name: name,
|
||||||
|
pipeline: pipeline,
|
||||||
|
marker_types: marker_types,
|
||||||
|
script_sender: script_sender,
|
||||||
|
is_recording: Arc::new(Mutex::new(false)),
|
||||||
|
stream: RefCell::new(None),
|
||||||
|
|
||||||
|
framerate_actor: RefCell::new(None),
|
||||||
|
memory_actor: RefCell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pull_timeline_data(&self, receiver: Receiver<TimelineMarker>, mut emitter: Emitter) {
|
||||||
|
let is_recording = self.is_recording.clone();
|
||||||
|
|
||||||
|
if !*is_recording.lock().unwrap() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Select root(with depth 0) TimelineMarker pair (IntervalStart + IntervalEnd)
|
||||||
|
/// from queue and add marker to emitter
|
||||||
|
/// Return true if closed (IntervalStart + IntervalEnd) pair was founded
|
||||||
|
fn group(queue: &mut VecDeque<TimelineMarker>, depth: usize,
|
||||||
|
start_payload: Option<TimelineMarker>, emitter: &mut Emitter) -> bool {
|
||||||
|
|
||||||
|
if let Some(start_payload) = start_payload {
|
||||||
|
if start_payload.metadata != TracingMetadata::IntervalStart {
|
||||||
|
panic!("Start payload doesn't have metadata IntervalStart");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(end_payload) = queue.pop_front() {
|
||||||
|
match end_payload.metadata {
|
||||||
|
TracingMetadata::IntervalEnd => {
|
||||||
|
if depth == 0 {
|
||||||
|
// Emit TimelineMarkerReply, pair was found
|
||||||
|
emitter.add_marker(start_payload, end_payload);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
TracingMetadata::IntervalStart => {
|
||||||
|
if group(queue, depth + 1, Some(end_payload), emitter) {
|
||||||
|
return group(queue, depth, Some(start_payload), emitter);
|
||||||
|
} else {
|
||||||
|
queue.push_front(start_payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Unknown tracingMetadata")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
queue.push_front(start_payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
task::spawn_named("PullTimelineMarkers".to_string(), move || {
|
||||||
|
let mut queues = HashMap::new();
|
||||||
|
queues.insert("Reflow".to_string(), VecDeque::new());
|
||||||
|
queues.insert("DOMEvent".to_string(), VecDeque::new());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if !*is_recording.lock().unwrap() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating queues by marker.name
|
||||||
|
loop {
|
||||||
|
match receiver.try_recv() {
|
||||||
|
Ok(marker) => {
|
||||||
|
if let Some(list) = queues.get_mut(&marker.name) {
|
||||||
|
list.push_back(marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(TryRecvError) => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit all markers
|
||||||
|
for (_, queue) in queues.iter_mut() {
|
||||||
|
let start_payload = queue.pop_front();
|
||||||
|
group(queue, 0, start_payload, &mut emitter);
|
||||||
|
}
|
||||||
|
emitter.send();
|
||||||
|
|
||||||
|
sleep(Duration::milliseconds(DEFAULT_TIMELINE_DATA_PULL_TIMEOUT as i64));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Actor for TimelineActor {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_message(&self,
|
||||||
|
registry: &ActorRegistry,
|
||||||
|
msg_type: &str,
|
||||||
|
msg: &json::Object,
|
||||||
|
stream: &mut TcpStream) -> Result<bool, ()> {
|
||||||
|
Ok(match msg_type {
|
||||||
|
"start" => {
|
||||||
|
**self.is_recording.lock().as_mut().unwrap() = true;
|
||||||
|
|
||||||
|
let (tx, rx) = channel::<TimelineMarker>();
|
||||||
|
self.script_sender.send(SetTimelineMarkers(self.pipeline, self.marker_types.clone(), tx));
|
||||||
|
|
||||||
|
*self.stream.borrow_mut() = stream.try_clone().ok();
|
||||||
|
|
||||||
|
// init memory actor
|
||||||
|
if let Some(with_memory) = msg.get("withMemory") {
|
||||||
|
if let Some(true) = with_memory.as_boolean() {
|
||||||
|
*self.memory_actor.borrow_mut() = Some(MemoryActor::create(registry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// init framerate actor
|
||||||
|
if let Some(with_ticks) = msg.get("withTicks") {
|
||||||
|
if let Some(true) = with_ticks.as_boolean() {
|
||||||
|
*self.framerate_actor.borrow_mut() = Some(FramerateActor::create(registry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let emitter = Emitter::new(self.name(), registry.get_shareable(),
|
||||||
|
stream.try_clone().unwrap(),
|
||||||
|
self.memory_actor.borrow().clone(),
|
||||||
|
self.framerate_actor.borrow().clone());
|
||||||
|
|
||||||
|
self.pull_timeline_data(rx, emitter);
|
||||||
|
|
||||||
|
let msg = StartReply {
|
||||||
|
from: self.name(),
|
||||||
|
value: precise_time_ns(),
|
||||||
|
};
|
||||||
|
stream.write_json_packet(&msg);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
"stop" => {
|
||||||
|
let msg = StopReply {
|
||||||
|
from: self.name(),
|
||||||
|
value: precise_time_ns()
|
||||||
|
};
|
||||||
|
|
||||||
|
stream.write_json_packet(&msg);
|
||||||
|
self.script_sender.send(DropTimelineMarkers(self.pipeline, self.marker_types.clone()));
|
||||||
|
|
||||||
|
if let Some(ref actor_name) = *self.framerate_actor.borrow() {
|
||||||
|
registry.drop_actor_later(actor_name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref actor_name) = *self.memory_actor.borrow() {
|
||||||
|
registry.drop_actor_later(actor_name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
**self.is_recording.lock().as_mut().unwrap() = false;
|
||||||
|
self.stream.borrow_mut().take();
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
"isRecording" => {
|
||||||
|
let msg = IsRecordingReply {
|
||||||
|
from: self.name(),
|
||||||
|
value: self.is_recording.lock().unwrap().clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
stream.write_json_packet(&msg);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Emitter {
|
||||||
|
pub fn new(name: String,
|
||||||
|
registry: Arc<Mutex<ActorRegistry>>,
|
||||||
|
stream: TcpStream,
|
||||||
|
memory_actor_name: Option<String>,
|
||||||
|
framerate_actor_name: Option<String>) -> Emitter {
|
||||||
|
|
||||||
|
Emitter {
|
||||||
|
from: name,
|
||||||
|
stream: stream,
|
||||||
|
markers: Vec::new(),
|
||||||
|
registry: registry,
|
||||||
|
|
||||||
|
framerate_actor: framerate_actor_name,
|
||||||
|
memory_actor: memory_actor_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_marker(&mut self, start_payload: TimelineMarker, end_payload: TimelineMarker) -> () {
|
||||||
|
self.markers.push(TimelineMarkerReply {
|
||||||
|
name: start_payload.name,
|
||||||
|
start: start_payload.time,
|
||||||
|
end: end_payload.time,
|
||||||
|
stack: start_payload.stack,
|
||||||
|
endStack: end_payload.stack,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(&mut self) -> () {
|
||||||
|
let end_time = precise_time_ns();
|
||||||
|
let reply = MarkersEmitterReply {
|
||||||
|
__type__: "markers".to_string(),
|
||||||
|
markers: Vec::from_iter(self.markers.drain()),
|
||||||
|
from: self.from.clone(),
|
||||||
|
endTime: end_time,
|
||||||
|
};
|
||||||
|
self.stream.write_json_packet(&reply);
|
||||||
|
|
||||||
|
if let Some(ref actor_name) = self.framerate_actor {
|
||||||
|
let mut lock = self.registry.lock();
|
||||||
|
let registry = lock.as_mut().unwrap();
|
||||||
|
let mut framerate_actor = registry.find_mut::<FramerateActor>(actor_name);
|
||||||
|
let framerateReply = FramerateEmitterReply {
|
||||||
|
__type__: "framerate".to_string(),
|
||||||
|
from: framerate_actor.name(),
|
||||||
|
delta: end_time,
|
||||||
|
timestamps: framerate_actor.take_pending_ticks(),
|
||||||
|
};
|
||||||
|
self.stream.write_json_packet(&framerateReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref actor_name) = self.memory_actor {
|
||||||
|
let registry = self.registry.lock().unwrap();
|
||||||
|
let memory_actor = registry.find::<MemoryActor>(actor_name);
|
||||||
|
let memoryReply = MemoryEmitterReply {
|
||||||
|
__type__: "memory".to_string(),
|
||||||
|
from: memory_actor.name(),
|
||||||
|
delta: end_time,
|
||||||
|
measurement: memory_actor.measure(),
|
||||||
|
};
|
||||||
|
self.stream.write_json_packet(&memoryReply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use actor::{Actor, ActorRegistry};
|
use actor::{Actor, ActorRegistry};
|
||||||
|
use msg::constellation_msg::WorkerId;
|
||||||
use rustc_serialize::json;
|
use rustc_serialize::json;
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use msg::constellation_msg::WorkerId;
|
|
||||||
|
|
||||||
pub struct WorkerActor {
|
pub struct WorkerActor {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
|
@ -34,6 +34,7 @@ use actors::worker::WorkerActor;
|
||||||
use actors::inspector::InspectorActor;
|
use actors::inspector::InspectorActor;
|
||||||
use actors::root::RootActor;
|
use actors::root::RootActor;
|
||||||
use actors::tab::TabActor;
|
use actors::tab::TabActor;
|
||||||
|
use actors::timeline::TimelineActor;
|
||||||
use protocol::JsonPacketStream;
|
use protocol::JsonPacketStream;
|
||||||
|
|
||||||
use devtools_traits::{ConsoleMessage, DevtoolsControlMsg};
|
use devtools_traits::{ConsoleMessage, DevtoolsControlMsg};
|
||||||
|
@ -53,9 +54,12 @@ mod actor;
|
||||||
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
|
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
|
||||||
mod actors {
|
mod actors {
|
||||||
pub mod console;
|
pub mod console;
|
||||||
|
pub mod framerate;
|
||||||
|
pub mod memory;
|
||||||
pub mod inspector;
|
pub mod inspector;
|
||||||
pub mod root;
|
pub mod root;
|
||||||
pub mod tab;
|
pub mod tab;
|
||||||
|
pub mod timeline;
|
||||||
pub mod worker;
|
pub mod worker;
|
||||||
}
|
}
|
||||||
mod protocol;
|
mod protocol;
|
||||||
|
@ -103,7 +107,7 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
||||||
registry.register(root);
|
registry.register(root);
|
||||||
registry.find::<RootActor>("root");
|
registry.find::<RootActor>("root");
|
||||||
|
|
||||||
let actors = Arc::new(Mutex::new(registry));
|
let actors = registry.create_shareable();
|
||||||
|
|
||||||
let mut accepted_connections: Vec<TcpStream> = Vec::new();
|
let mut accepted_connections: Vec<TcpStream> = Vec::new();
|
||||||
|
|
||||||
|
@ -122,9 +126,8 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
match stream.read_json_packet() {
|
match stream.read_json_packet() {
|
||||||
Ok(json_packet) => {
|
Ok(json_packet) => {
|
||||||
let mut actors = actors.lock().unwrap();
|
match actors.lock().unwrap().handle_message(json_packet.as_object().unwrap(),
|
||||||
match actors.handle_message(json_packet.as_object().unwrap(),
|
&mut stream) {
|
||||||
&mut stream) {
|
|
||||||
Ok(()) => {},
|
Ok(()) => {},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
println!("error: devtools actor stopped responding");
|
println!("error: devtools actor stopped responding");
|
||||||
|
@ -156,7 +159,7 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
||||||
let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new();
|
let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new();
|
||||||
|
|
||||||
//TODO: move all this actor creation into a constructor method on TabActor
|
//TODO: move all this actor creation into a constructor method on TabActor
|
||||||
let (tab, console, inspector) = {
|
let (tab, console, inspector, timeline) = {
|
||||||
let console = ConsoleActor {
|
let console = ConsoleActor {
|
||||||
name: actors.new_name("console"),
|
name: actors.new_name("console"),
|
||||||
script_chan: scriptSender.clone(),
|
script_chan: scriptSender.clone(),
|
||||||
|
@ -168,10 +171,14 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
||||||
walker: RefCell::new(None),
|
walker: RefCell::new(None),
|
||||||
pageStyle: RefCell::new(None),
|
pageStyle: RefCell::new(None),
|
||||||
highlighter: RefCell::new(None),
|
highlighter: RefCell::new(None),
|
||||||
script_chan: scriptSender,
|
script_chan: scriptSender.clone(),
|
||||||
pipeline: pipeline,
|
pipeline: pipeline,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let timeline = TimelineActor::new(actors.new_name("timeline"),
|
||||||
|
pipeline,
|
||||||
|
scriptSender);
|
||||||
|
|
||||||
let DevtoolsPageInfo { title, url } = page_info;
|
let DevtoolsPageInfo { title, url } = page_info;
|
||||||
let tab = TabActor {
|
let tab = TabActor {
|
||||||
name: actors.new_name("tab"),
|
name: actors.new_name("tab"),
|
||||||
|
@ -179,11 +186,12 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
||||||
url: url.serialize(),
|
url: url.serialize(),
|
||||||
console: console.name(),
|
console: console.name(),
|
||||||
inspector: inspector.name(),
|
inspector: inspector.name(),
|
||||||
|
timeline: timeline.name(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let root = actors.find_mut::<RootActor>("root");
|
let root = actors.find_mut::<RootActor>("root");
|
||||||
root.tabs.push(tab.name.clone());
|
root.tabs.push(tab.name.clone());
|
||||||
(tab, console, inspector)
|
(tab, console, inspector, timeline)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(id) = worker_id {
|
if let Some(id) = worker_id {
|
||||||
|
@ -199,6 +207,7 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
||||||
actors.register(box tab);
|
actors.register(box tab);
|
||||||
actors.register(box console);
|
actors.register(box console);
|
||||||
actors.register(box inspector);
|
actors.register(box inspector);
|
||||||
|
actors.register(box timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_console_message(actors: Arc<Mutex<ActorRegistry>>,
|
fn handle_console_message(actors: Arc<Mutex<ActorRegistry>>,
|
||||||
|
|
|
@ -15,4 +15,7 @@ path = "../util"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
url = "0.2.16"
|
url = "0.2.16"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
time = "*"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
|
|
|
@ -17,6 +17,7 @@ extern crate msg;
|
||||||
extern crate "rustc-serialize" as rustc_serialize;
|
extern crate "rustc-serialize" as rustc_serialize;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
extern crate util;
|
extern crate util;
|
||||||
|
extern crate time;
|
||||||
|
|
||||||
use rustc_serialize::{Decodable, Decoder};
|
use rustc_serialize::{Decodable, Decoder};
|
||||||
use msg::constellation_msg::{PipelineId, WorkerId};
|
use msg::constellation_msg::{PipelineId, WorkerId};
|
||||||
|
@ -83,6 +84,28 @@ pub struct NodeInfo {
|
||||||
pub incompleteValue: bool,
|
pub incompleteValue: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub enum TracingMetadata {
|
||||||
|
Default,
|
||||||
|
IntervalStart,
|
||||||
|
IntervalEnd,
|
||||||
|
Event,
|
||||||
|
EventBacktrace,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TimelineMarker {
|
||||||
|
pub name: String,
|
||||||
|
pub metadata: TracingMetadata,
|
||||||
|
pub time: u64,
|
||||||
|
pub stack: Option<Vec<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||||
|
pub enum TimelineMarkerType {
|
||||||
|
Reflow,
|
||||||
|
DOMEvent,
|
||||||
|
}
|
||||||
|
|
||||||
/// Messages to process in a particular script task, as instructed by a devtools client.
|
/// Messages to process in a particular script task, as instructed by a devtools client.
|
||||||
pub enum DevtoolScriptControlMsg {
|
pub enum DevtoolScriptControlMsg {
|
||||||
EvaluateJS(PipelineId, String, Sender<EvaluateJSReply>),
|
EvaluateJS(PipelineId, String, Sender<EvaluateJSReply>),
|
||||||
|
@ -92,6 +115,8 @@ pub enum DevtoolScriptControlMsg {
|
||||||
GetLayout(PipelineId, String, Sender<(f32, f32)>),
|
GetLayout(PipelineId, String, Sender<(f32, f32)>),
|
||||||
ModifyAttribute(PipelineId, String, Vec<Modification>),
|
ModifyAttribute(PipelineId, String, Vec<Modification>),
|
||||||
WantsLiveNotifications(PipelineId, bool),
|
WantsLiveNotifications(PipelineId, bool),
|
||||||
|
SetTimelineMarkers(PipelineId, Vec<TimelineMarkerType>, Sender<TimelineMarker>),
|
||||||
|
DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages to instruct devtools server to update its state relating to a particular
|
/// Messages to instruct devtools server to update its state relating to a particular
|
||||||
|
@ -128,3 +153,14 @@ pub enum ConsoleMessage {
|
||||||
LogMessage(String, String, u32, u32),
|
LogMessage(String, String, u32, u32),
|
||||||
//WarnMessage(String),
|
//WarnMessage(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TimelineMarker {
|
||||||
|
pub fn new(name: String, metadata: TracingMetadata) -> TimelineMarker {
|
||||||
|
TimelineMarker {
|
||||||
|
name: name,
|
||||||
|
metadata: metadata,
|
||||||
|
time: time::precise_time_ns(),
|
||||||
|
stack: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use devtools_traits::{EvaluateJSReply, NodeInfo, Modification};
|
use devtools_traits::{EvaluateJSReply, NodeInfo, Modification, TimelineMarker, TimelineMarkerType};
|
||||||
use dom::bindings::conversions::FromJSValConvertible;
|
use dom::bindings::conversions::FromJSValConvertible;
|
||||||
use dom::bindings::conversions::StringificationBehavior;
|
use dom::bindings::conversions::StringificationBehavior;
|
||||||
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
|
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
|
||||||
|
@ -16,7 +16,7 @@ use dom::element::Element;
|
||||||
use dom::document::DocumentHelpers;
|
use dom::document::DocumentHelpers;
|
||||||
use page::Page;
|
use page::Page;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use script_task::get_page;
|
use script_task::{get_page, ScriptTask};
|
||||||
|
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -114,3 +114,36 @@ pub fn handle_wants_live_notifications(page: &Rc<Page>, pipeline_id: PipelineId,
|
||||||
let window = page.window().root();
|
let window = page.window().root();
|
||||||
window.r().set_devtools_wants_updates(send_notifications);
|
window.r().set_devtools_wants_updates(send_notifications);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_set_timeline_markers(page: &Rc<Page>,
|
||||||
|
script_task: &ScriptTask,
|
||||||
|
marker_types: Vec<TimelineMarkerType>,
|
||||||
|
reply: Sender<TimelineMarker>) {
|
||||||
|
for marker_type in &marker_types {
|
||||||
|
match *marker_type {
|
||||||
|
TimelineMarkerType::Reflow => {
|
||||||
|
let window = page.window().root();
|
||||||
|
window.r().set_devtools_timeline_marker(TimelineMarkerType::Reflow, reply.clone());
|
||||||
|
}
|
||||||
|
TimelineMarkerType::DOMEvent => {
|
||||||
|
script_task.set_devtools_timeline_marker(TimelineMarkerType::DOMEvent, reply.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_drop_timeline_markers(page: &Rc<Page>,
|
||||||
|
script_task: &ScriptTask,
|
||||||
|
marker_types: Vec<TimelineMarkerType>) {
|
||||||
|
let window = page.window().root();
|
||||||
|
for marker_type in &marker_types {
|
||||||
|
match *marker_type {
|
||||||
|
TimelineMarkerType::Reflow => {
|
||||||
|
window.r().drop_devtools_timeline_markers();
|
||||||
|
}
|
||||||
|
TimelineMarkerType::DOMEvent => {
|
||||||
|
script_task.drop_devtools_timeline_markers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -241,6 +241,7 @@ no_jsmanaged_fields!(ImageCacheTask, ScriptControlChan);
|
||||||
no_jsmanaged_fields!(Atom, Namespace, Timer);
|
no_jsmanaged_fields!(Atom, Namespace, Timer);
|
||||||
no_jsmanaged_fields!(Trusted<T>);
|
no_jsmanaged_fields!(Trusted<T>);
|
||||||
no_jsmanaged_fields!(PropertyDeclarationBlock);
|
no_jsmanaged_fields!(PropertyDeclarationBlock);
|
||||||
|
no_jsmanaged_fields!(HashSet<T>);
|
||||||
// These three are interdependent, if you plan to put jsmanaged data
|
// These three are interdependent, if you plan to put jsmanaged data
|
||||||
// in one of these make sure it is propagated properly to containing structs
|
// in one of these make sure it is propagated properly to containing structs
|
||||||
no_jsmanaged_fields!(SubpageId, WindowSizeData, PipelineId);
|
no_jsmanaged_fields!(SubpageId, WindowSizeData, PipelineId);
|
||||||
|
|
|
@ -34,7 +34,7 @@ use script_task::ScriptMsg;
|
||||||
use script_traits::ScriptControlChan;
|
use script_traits::ScriptControlChan;
|
||||||
use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
|
use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
|
||||||
|
|
||||||
use devtools_traits::DevtoolsControlChan;
|
use devtools_traits::{DevtoolsControlChan, TimelineMarker, TimelineMarkerType, TracingMetadata};
|
||||||
use msg::compositor_msg::ScriptListener;
|
use msg::compositor_msg::ScriptListener;
|
||||||
use msg::constellation_msg::{LoadData, PipelineId, SubpageId, ConstellationChan, WindowSizeData, WorkerId};
|
use msg::constellation_msg::{LoadData, PipelineId, SubpageId, ConstellationChan, WindowSizeData, WorkerId};
|
||||||
use net_traits::ResourceTask;
|
use net_traits::ResourceTask;
|
||||||
|
@ -54,13 +54,15 @@ use url::{Url, UrlParser};
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};
|
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};
|
||||||
use std::cell::{Cell, Ref, RefMut};
|
use std::borrow::ToOwned;
|
||||||
|
use std::cell::{Cell, Ref, RefMut, RefCell};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num::Float;
|
use std::num::Float;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::{channel, Receiver};
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
use std::sync::mpsc::TryRecvError::{Empty, Disconnected};
|
use std::sync::mpsc::TryRecvError::{Empty, Disconnected};
|
||||||
use time;
|
use time;
|
||||||
|
|
||||||
|
@ -102,6 +104,10 @@ pub struct Window {
|
||||||
|
|
||||||
/// For providing instructions to an optional devtools server.
|
/// For providing instructions to an optional devtools server.
|
||||||
devtools_chan: Option<DevtoolsControlChan>,
|
devtools_chan: Option<DevtoolsControlChan>,
|
||||||
|
/// For sending timeline markers. Will be ignored if
|
||||||
|
/// no devtools server
|
||||||
|
devtools_markers: RefCell<HashSet<TimelineMarkerType>>,
|
||||||
|
devtools_marker_sender: RefCell<Option<Sender<TimelineMarker>>>,
|
||||||
|
|
||||||
/// A flag to indicate whether the developer tools have requested live updates of
|
/// A flag to indicate whether the developer tools have requested live updates of
|
||||||
/// page changes.
|
/// page changes.
|
||||||
|
@ -477,6 +483,10 @@ pub trait WindowHelpers {
|
||||||
fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>>;
|
fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>>;
|
||||||
fn thaw(self);
|
fn thaw(self);
|
||||||
fn freeze(self);
|
fn freeze(self);
|
||||||
|
fn need_emit_timeline_marker(self, timeline_type: TimelineMarkerType) -> bool;
|
||||||
|
fn emit_timeline_marker(self, marker: TimelineMarker);
|
||||||
|
fn set_devtools_timeline_marker(self, marker: TimelineMarkerType, reply: Sender<TimelineMarker>);
|
||||||
|
fn drop_devtools_timeline_markers(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ScriptHelpers {
|
pub trait ScriptHelpers {
|
||||||
|
@ -547,6 +557,11 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if self.need_emit_timeline_marker(TimelineMarkerType::Reflow) {
|
||||||
|
let marker = TimelineMarker::new("Reflow".to_owned(), TracingMetadata::IntervalStart);
|
||||||
|
self.emit_timeline_marker(marker);
|
||||||
|
}
|
||||||
|
|
||||||
// Layout will let us know when it's done.
|
// Layout will let us know when it's done.
|
||||||
let (join_chan, join_port) = channel();
|
let (join_chan, join_port) = channel();
|
||||||
|
|
||||||
|
@ -583,6 +598,11 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
|
||||||
debug!("script: layout forked");
|
debug!("script: layout forked");
|
||||||
|
|
||||||
self.join_layout();
|
self.join_layout();
|
||||||
|
|
||||||
|
if self.need_emit_timeline_marker(TimelineMarkerType::Reflow) {
|
||||||
|
let marker = TimelineMarker::new("Reflow".to_owned(), TracingMetadata::IntervalEnd);
|
||||||
|
self.emit_timeline_marker(marker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(cgaebel): join_layout is racey. What if the compositor triggers a
|
// FIXME(cgaebel): join_layout is racey. What if the compositor triggers a
|
||||||
|
@ -776,6 +796,27 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
|
||||||
fn freeze(self) {
|
fn freeze(self) {
|
||||||
self.timers.suspend();
|
self.timers.suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn need_emit_timeline_marker(self, timeline_type: TimelineMarkerType) -> bool {
|
||||||
|
let markers = self.devtools_markers.borrow();
|
||||||
|
markers.contains(&timeline_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_timeline_marker(self, marker: TimelineMarker) {
|
||||||
|
let sender = self.devtools_marker_sender.borrow();
|
||||||
|
let sender = sender.as_ref().expect("There is no marker sender");
|
||||||
|
sender.send(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_devtools_timeline_marker(self, marker: TimelineMarkerType, reply: Sender<TimelineMarker>) {
|
||||||
|
*self.devtools_marker_sender.borrow_mut() = Some(reply);
|
||||||
|
self.devtools_markers.borrow_mut().insert(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop_devtools_timeline_markers(self) {
|
||||||
|
self.devtools_markers.borrow_mut().clear();
|
||||||
|
*self.devtools_marker_sender.borrow_mut() = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
@ -836,6 +877,9 @@ impl Window {
|
||||||
layout_rpc: layout_rpc,
|
layout_rpc: layout_rpc,
|
||||||
layout_join_port: DOMRefCell::new(None),
|
layout_join_port: DOMRefCell::new(None),
|
||||||
window_size: Cell::new(window_size),
|
window_size: Cell::new(window_size),
|
||||||
|
|
||||||
|
devtools_marker_sender: RefCell::new(None),
|
||||||
|
devtools_markers: RefCell::new(HashSet::new()),
|
||||||
devtools_wants_updates: Cell::new(false),
|
devtools_wants_updates: Cell::new(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ use devtools;
|
||||||
|
|
||||||
use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, DevtoolsPageInfo};
|
use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, DevtoolsPageInfo};
|
||||||
use devtools_traits::{DevtoolsControlMsg, DevtoolScriptControlMsg};
|
use devtools_traits::{DevtoolsControlMsg, DevtoolScriptControlMsg};
|
||||||
|
use devtools_traits::{TimelineMarker, TimelineMarkerType, TracingMetadata};
|
||||||
use script_traits::CompositorEvent;
|
use script_traits::CompositorEvent;
|
||||||
use script_traits::CompositorEvent::{ResizeEvent, ReflowEvent, ClickEvent};
|
use script_traits::CompositorEvent::{ResizeEvent, ReflowEvent, ClickEvent};
|
||||||
use script_traits::CompositorEvent::{MouseDownEvent, MouseUpEvent};
|
use script_traits::CompositorEvent::{MouseDownEvent, MouseUpEvent};
|
||||||
|
@ -86,6 +87,7 @@ use std::ascii::AsciiExt;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::num::ToPrimitive;
|
use std::num::ToPrimitive;
|
||||||
use std::option::Option;
|
use std::option::Option;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -279,6 +281,10 @@ pub struct ScriptTask {
|
||||||
/// no such server exists.
|
/// no such server exists.
|
||||||
devtools_port: DevtoolsControlPort,
|
devtools_port: DevtoolsControlPort,
|
||||||
devtools_sender: Sender<DevtoolScriptControlMsg>,
|
devtools_sender: Sender<DevtoolScriptControlMsg>,
|
||||||
|
/// For sending timeline markers. Will be ignored if
|
||||||
|
/// no devtools server
|
||||||
|
devtools_markers: RefCell<HashSet<TimelineMarkerType>>,
|
||||||
|
devtools_marker_sender: RefCell<Option<Sender<TimelineMarker>>>,
|
||||||
|
|
||||||
/// The JavaScript runtime.
|
/// The JavaScript runtime.
|
||||||
js_runtime: js::rust::rt,
|
js_runtime: js::rust::rt,
|
||||||
|
@ -447,6 +453,8 @@ impl ScriptTask {
|
||||||
devtools_chan: devtools_chan,
|
devtools_chan: devtools_chan,
|
||||||
devtools_port: devtools_receiver,
|
devtools_port: devtools_receiver,
|
||||||
devtools_sender: devtools_sender,
|
devtools_sender: devtools_sender,
|
||||||
|
devtools_markers: RefCell::new(HashSet::new()),
|
||||||
|
devtools_marker_sender: RefCell::new(None),
|
||||||
|
|
||||||
js_runtime: js_runtime,
|
js_runtime: js_runtime,
|
||||||
js_context: DOMRefCell::new(Some(js_context)),
|
js_context: DOMRefCell::new(Some(js_context)),
|
||||||
|
@ -700,6 +708,10 @@ impl ScriptTask {
|
||||||
devtools::handle_modify_attribute(&page, id, node_id, modifications),
|
devtools::handle_modify_attribute(&page, id, node_id, modifications),
|
||||||
DevtoolScriptControlMsg::WantsLiveNotifications(pipeline_id, to_send) =>
|
DevtoolScriptControlMsg::WantsLiveNotifications(pipeline_id, to_send) =>
|
||||||
devtools::handle_wants_live_notifications(&page, pipeline_id, to_send),
|
devtools::handle_wants_live_notifications(&page, pipeline_id, to_send),
|
||||||
|
DevtoolScriptControlMsg::SetTimelineMarkers(_pipeline_id, marker_types, reply) =>
|
||||||
|
devtools::handle_set_timeline_markers(&page, self, marker_types, reply),
|
||||||
|
DevtoolScriptControlMsg::DropTimelineMarkers(_pipeline_id, marker_types) =>
|
||||||
|
devtools::handle_drop_timeline_markers(&page, self, marker_types),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1150,8 +1162,14 @@ impl ScriptTask {
|
||||||
///
|
///
|
||||||
/// TODO: Actually perform DOM event dispatch.
|
/// TODO: Actually perform DOM event dispatch.
|
||||||
fn handle_event(&self, pipeline_id: PipelineId, event: CompositorEvent) {
|
fn handle_event(&self, pipeline_id: PipelineId, event: CompositorEvent) {
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
ResizeEvent(new_size) => {
|
ResizeEvent(new_size) => {
|
||||||
|
let _marker;
|
||||||
|
if self.need_emit_timeline_marker(TimelineMarkerType::DOMEvent) {
|
||||||
|
_marker = AutoDOMEventMarker::new(self);
|
||||||
|
}
|
||||||
|
|
||||||
self.handle_resize_event(pipeline_id, new_size);
|
self.handle_resize_event(pipeline_id, new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1179,6 +1197,10 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
ClickEvent(button, point) => {
|
ClickEvent(button, point) => {
|
||||||
|
let _marker;
|
||||||
|
if self.need_emit_timeline_marker(TimelineMarkerType::DOMEvent) {
|
||||||
|
_marker = AutoDOMEventMarker::new(self);
|
||||||
|
}
|
||||||
let page = get_page(&self.root_page(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let document = page.document().root();
|
let document = page.document().root();
|
||||||
document.r().handle_click_event(self.js_runtime.ptr, button, point);
|
document.r().handle_click_event(self.js_runtime.ptr, button, point);
|
||||||
|
@ -1187,6 +1209,10 @@ impl ScriptTask {
|
||||||
MouseDownEvent(..) => {}
|
MouseDownEvent(..) => {}
|
||||||
MouseUpEvent(..) => {}
|
MouseUpEvent(..) => {}
|
||||||
MouseMoveEvent(point) => {
|
MouseMoveEvent(point) => {
|
||||||
|
let _marker;
|
||||||
|
if self.need_emit_timeline_marker(TimelineMarkerType::DOMEvent) {
|
||||||
|
_marker = AutoDOMEventMarker::new(self);
|
||||||
|
}
|
||||||
let page = get_page(&self.root_page(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let document = page.document().root();
|
let document = page.document().root();
|
||||||
let mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut();
|
let mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut();
|
||||||
|
@ -1195,6 +1221,10 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent(key, state, modifiers) => {
|
KeyEvent(key, state, modifiers) => {
|
||||||
|
let _marker;
|
||||||
|
if self.need_emit_timeline_marker(TimelineMarkerType::DOMEvent) {
|
||||||
|
_marker = AutoDOMEventMarker::new(self);
|
||||||
|
}
|
||||||
let page = get_page(&self.root_page(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let document = page.document().root();
|
let document = page.document().root();
|
||||||
document.r().dispatch_key_event(
|
document.r().dispatch_key_event(
|
||||||
|
@ -1311,6 +1341,26 @@ impl ScriptTask {
|
||||||
|
|
||||||
self.incomplete_loads.borrow_mut().push(incomplete);
|
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool {
|
||||||
|
self.devtools_markers.borrow().contains(&timeline_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_timeline_marker(&self, marker: TimelineMarker) {
|
||||||
|
let sender = self.devtools_marker_sender.borrow();
|
||||||
|
let sender = sender.as_ref().expect("There is no marker sender");
|
||||||
|
sender.send(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_devtools_timeline_marker(&self, marker: TimelineMarkerType, reply: Sender<TimelineMarker>) {
|
||||||
|
*self.devtools_marker_sender.borrow_mut() = Some(reply);
|
||||||
|
self.devtools_markers.borrow_mut().insert(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drop_devtools_timeline_markers(&self) {
|
||||||
|
self.devtools_markers.borrow_mut().clear();
|
||||||
|
*self.devtools_marker_sender.borrow_mut() = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ScriptTask {
|
impl Drop for ScriptTask {
|
||||||
|
@ -1321,6 +1371,28 @@ impl Drop for ScriptTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AutoDOMEventMarker<'a> {
|
||||||
|
script_task: &'a ScriptTask
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AutoDOMEventMarker<'a> {
|
||||||
|
fn new(script_task: &'a ScriptTask) -> AutoDOMEventMarker<'a> {
|
||||||
|
let marker = TimelineMarker::new("DOMEvent".to_owned(), TracingMetadata::IntervalStart);
|
||||||
|
script_task.emit_timeline_marker(marker);
|
||||||
|
AutoDOMEventMarker {
|
||||||
|
script_task: script_task
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl<'a> Drop for AutoDOMEventMarker<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let marker = TimelineMarker::new("DOMEvent".to_owned(), TracingMetadata::IntervalEnd);
|
||||||
|
self.script_task.emit_timeline_marker(marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Shuts down layout for the given page tree.
|
/// Shuts down layout for the given page tree.
|
||||||
fn shut_down_layout(page_tree: &Rc<Page>, exit_type: PipelineExitType) {
|
fn shut_down_layout(page_tree: &Rc<Page>, exit_type: PipelineExitType) {
|
||||||
let mut channels = vec!();
|
let mut channels = vec!();
|
||||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -173,6 +173,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
"rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"util 0.0.1",
|
"util 0.0.1",
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue