Support multiprocess in sampling profiler.

This commit is contained in:
Josh Matthews 2019-03-25 14:10:44 -04:00
parent 90f67c11e5
commit 8b7244f0d1
9 changed files with 165 additions and 117 deletions

1
Cargo.lock generated
View file

@ -152,7 +152,6 @@ dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-channel 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -16,7 +16,6 @@ doctest = false
backtrace = "0.3" backtrace = "0.3"
bitflags = "1.0" bitflags = "1.0"
ipc-channel = "0.11" ipc-channel = "0.11"
lazy_static = "1"
libc = "0.2" libc = "0.2"
log = "0.4" log = "0.4"
msg = {path = "../msg"} msg = {path = "../msg"}

View file

@ -4,15 +4,15 @@
use crate::sampler::{NativeStack, Sampler}; use crate::sampler::{NativeStack, Sampler};
use crossbeam_channel::{after, unbounded, Receiver, Sender}; use crossbeam_channel::{after, unbounded, Receiver, Sender};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use msg::constellation_msg::MonitoredComponentId; use msg::constellation_msg::MonitoredComponentId;
use msg::constellation_msg::{ use msg::constellation_msg::{
BackgroundHangMonitor, BackgroundHangMonitorClone, BackgroundHangMonitorRegister, BackgroundHangMonitor, BackgroundHangMonitorClone, BackgroundHangMonitorRegister,
}; };
use msg::constellation_msg::{HangAlert, HangAnnotation, HangMonitorAlert}; use msg::constellation_msg::{HangAlert, HangAnnotation, HangMonitorAlert, SamplerControlMsg};
use std::cell::Cell; use std::cell::Cell;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Mutex;
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -21,46 +21,22 @@ pub struct HangMonitorRegister {
sender: Sender<(MonitoredComponentId, MonitoredComponentMsg)>, sender: Sender<(MonitoredComponentId, MonitoredComponentMsg)>,
} }
#[derive(Copy, Clone, PartialEq)]
enum SamplerState {
NotSampling,
StartSampling(Duration),
Sampling,
Resolving,
}
lazy_static! {
static ref SAMPLING_STATE: Mutex<SamplerState> = Mutex::new(SamplerState::NotSampling);
}
impl HangMonitorRegister { impl HangMonitorRegister {
/// Start a new hang monitor worker, and return a handle to register components for monitoring. /// Start a new hang monitor worker, and return a handle to register components for monitoring.
pub fn init( pub fn init(
constellation_chan: IpcSender<HangMonitorAlert>, constellation_chan: IpcSender<HangMonitorAlert>,
control_port: IpcReceiver<SamplerControlMsg>,
) -> Box<BackgroundHangMonitorRegister> { ) -> Box<BackgroundHangMonitorRegister> {
let (sender, port) = unbounded(); let (sender, port) = unbounded();
let _ = thread::Builder::new().spawn(move || { let _ = thread::Builder::new().spawn(move || {
let mut monitor = BackgroundHangMonitorWorker::new(constellation_chan, port); let mut monitor =
BackgroundHangMonitorWorker::new(constellation_chan, control_port, port);
while monitor.run() { while monitor.run() {
// Monitoring until all senders have been dropped... // Monitoring until all senders have been dropped...
} }
}); });
Box::new(HangMonitorRegister { sender }) Box::new(HangMonitorRegister { sender })
} }
pub fn toggle(rate: Duration) {
let state = *SAMPLING_STATE.lock().unwrap();
match state {
SamplerState::NotSampling => {
println!("Starting profiler.");
*SAMPLING_STATE.lock().unwrap() = SamplerState::StartSampling(rate);
},
SamplerState::Sampling => {
println!("Stopping profiler.");
*SAMPLING_STATE.lock().unwrap() = SamplerState::Resolving;
},
_ => (),
}
}
} }
impl BackgroundHangMonitorRegister for HangMonitorRegister { impl BackgroundHangMonitorRegister for HangMonitorRegister {
@ -175,6 +151,7 @@ pub struct BackgroundHangMonitorWorker {
monitored_components: HashMap<MonitoredComponentId, MonitoredComponent>, monitored_components: HashMap<MonitoredComponentId, MonitoredComponent>,
constellation_chan: IpcSender<HangMonitorAlert>, constellation_chan: IpcSender<HangMonitorAlert>,
port: Receiver<(MonitoredComponentId, MonitoredComponentMsg)>, port: Receiver<(MonitoredComponentId, MonitoredComponentMsg)>,
control_port: Receiver<SamplerControlMsg>,
sampling_duration: Option<Duration>, sampling_duration: Option<Duration>,
last_sample: Instant, last_sample: Instant,
creation: Instant, creation: Instant,
@ -185,13 +162,16 @@ pub struct BackgroundHangMonitorWorker {
impl BackgroundHangMonitorWorker { impl BackgroundHangMonitorWorker {
pub fn new( pub fn new(
constellation_chan: IpcSender<HangMonitorAlert>, constellation_chan: IpcSender<HangMonitorAlert>,
control_port: IpcReceiver<SamplerControlMsg>,
port: Receiver<(MonitoredComponentId, MonitoredComponentMsg)>, port: Receiver<(MonitoredComponentId, MonitoredComponentMsg)>,
) -> Self { ) -> Self {
let control_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(control_port);
Self { Self {
component_names: Default::default(), component_names: Default::default(),
monitored_components: Default::default(), monitored_components: Default::default(),
constellation_chan, constellation_chan,
port, port,
control_port,
sampling_duration: None, sampling_duration: None,
last_sample: Instant::now(), last_sample: Instant::now(),
sampling_baseline: Instant::now(), sampling_baseline: Instant::now(),
@ -200,64 +180,48 @@ impl BackgroundHangMonitorWorker {
} }
} }
fn handle_sampling(&mut self) { fn finish_sampled_profile(&mut self) {
let state = *SAMPLING_STATE.lock().unwrap(); let mut bytes = vec![];
match state { bytes.extend(
SamplerState::StartSampling(rate) => { format!(
*SAMPLING_STATE.lock().unwrap() = SamplerState::Sampling; "{{ \"rate\": {}, \"start\": {}, \"data\": [\n",
self.sampling_duration = Some(rate); self.sampling_duration.unwrap().as_millis(),
self.sampling_baseline = Instant::now(); (self.sampling_baseline - self.creation).as_millis(),
}, )
SamplerState::Resolving => { .as_bytes(),
let mut bytes = vec![]; );
bytes.extend(
format!(
"{{ \"rate\": {}, \"start\": {}, \"data\": [\n",
self.sampling_duration.unwrap().as_millis(),
(self.sampling_baseline - self.creation).as_millis(),
)
.as_bytes(),
);
let mut first = true; let mut first = true;
let to_resolve = self.samples.len(); let to_resolve = self.samples.len();
for (i, Sample(id, instant, stack)) in self.samples.drain(..).enumerate() { for (i, Sample(id, instant, stack)) in self.samples.drain(..).enumerate() {
println!("Resolving {}/{}", i + 1, to_resolve); println!("Resolving {}/{}", i + 1, to_resolve);
let profile = stack.to_hangprofile(); let profile = stack.to_hangprofile();
let name = match self.component_names.get(&id) { let name = match self.component_names.get(&id) {
Some(ref s) => format!("\"{}\"", s), Some(ref s) => format!("\"{}\"", s),
None => format!("null"), None => format!("null"),
}; };
let json = format!( let json = format!(
"{}{{ \"name\": {}, \"namespace\": {}, \"index\": {}, \"type\": \"{:?}\", \ "{}{{ \"name\": {}, \"namespace\": {}, \"index\": {}, \"type\": \"{:?}\", \
\"time\": {}, \"frames\": {} }}", \"time\": {}, \"frames\": {} }}",
if !first { ",\n" } else { "" }, if !first { ",\n" } else { "" },
name, name,
id.0.namespace_id.0, id.0.namespace_id.0,
id.0.index.0.get(), id.0.index.0.get(),
id.1, id.1,
(instant - self.sampling_baseline).as_millis(), (instant - self.sampling_baseline).as_millis(),
serde_json::to_string(&profile.backtrace).unwrap(), serde_json::to_string(&profile.backtrace).unwrap(),
); );
bytes.extend(json.as_bytes()); bytes.extend(json.as_bytes());
first = false; first = false;
}
bytes.extend(b"\n] }");
let _ = self
.constellation_chan
.send(HangMonitorAlert::Profile(bytes));
*SAMPLING_STATE.lock().unwrap() = SamplerState::NotSampling;
self.sampling_duration = None;
},
_ => (),
} }
bytes.extend(b"\n] }");
let _ = self
.constellation_chan
.send(HangMonitorAlert::Profile(bytes));
} }
pub fn run(&mut self) -> bool { pub fn run(&mut self) -> bool {
self.handle_sampling();
let timeout = if let Some(duration) = self.sampling_duration { let timeout = if let Some(duration) = self.sampling_duration {
duration duration
.checked_sub(Instant::now() - self.last_sample) .checked_sub(Instant::now() - self.last_sample)
@ -273,6 +237,23 @@ impl BackgroundHangMonitorWorker {
Err(_) => return false, Err(_) => return false,
} }
}, },
recv(self.control_port) -> event => {
match event {
Ok(SamplerControlMsg::Enable(rate)) => {
println!("Enabling profiler.");
self.sampling_duration = Some(rate);
self.sampling_baseline = Instant::now();
None
}
Ok(SamplerControlMsg::Disable) => {
println!("Disabling profiler.");
self.finish_sampled_profile();
self.sampling_duration = None;
None
}
Err(_) => return false,
}
}
recv(after(timeout)) -> _ => None, recv(after(timeout)) -> _ => None,
}; };
if let Some(msg) = received { if let Some(msg) = received {
@ -285,9 +266,10 @@ impl BackgroundHangMonitorWorker {
} }
if let Some(duration) = self.sampling_duration { if let Some(duration) = self.sampling_duration {
if Instant::now() - self.last_sample > duration { let now = Instant::now();
if now - self.last_sample > duration {
self.sample(); self.sample();
self.last_sample = Instant::now(); self.last_sample = now;
} }
} else { } else {
self.perform_a_hang_monitor_checkpoint(); self.perform_a_hang_monitor_checkpoint();

View file

@ -7,8 +7,6 @@
#[macro_use] #[macro_use]
extern crate crossbeam_channel; extern crate crossbeam_channel;
#[macro_use] #[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log; extern crate log;
pub mod background_hang_monitor; pub mod background_hang_monitor;

View file

@ -124,7 +124,7 @@ use keyboard_types::webdriver::Event as WebDriverInputEvent;
use keyboard_types::KeyboardEvent; use keyboard_types::KeyboardEvent;
use layout_traits::LayoutThreadFactory; use layout_traits::LayoutThreadFactory;
use log::{Level, LevelFilter, Log, Metadata, Record}; use log::{Level, LevelFilter, Log, Metadata, Record};
use msg::constellation_msg::{BackgroundHangMonitorRegister, HangMonitorAlert}; use msg::constellation_msg::{BackgroundHangMonitorRegister, HangMonitorAlert, SamplerControlMsg};
use msg::constellation_msg::{ use msg::constellation_msg::{
BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId, BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId,
}; };
@ -208,6 +208,9 @@ pub struct Constellation<Message, LTF, STF> {
/// None when in multiprocess mode. /// None when in multiprocess mode.
background_monitor_register: Option<Box<BackgroundHangMonitorRegister>>, background_monitor_register: Option<Box<BackgroundHangMonitorRegister>>,
/// Channels to control all sampling profilers.
sampling_profiler_control: Vec<IpcSender<SamplerControlMsg>>,
/// A channel for the background hang monitor to send messages /// A channel for the background hang monitor to send messages
/// to the constellation. /// to the constellation.
background_hang_monitor_sender: IpcSender<HangMonitorAlert>, background_hang_monitor_sender: IpcSender<HangMonitorAlert>,
@ -614,12 +617,19 @@ where
// If we are in multiprocess mode, // If we are in multiprocess mode,
// a dedicated per-process hang monitor will be initialized later inside the content process. // a dedicated per-process hang monitor will be initialized later inside the content process.
// See run_content_process in servo/lib.rs // See run_content_process in servo/lib.rs
let background_monitor_register = if opts::multiprocess() { let (background_monitor_register, sampler_chan) = if opts::multiprocess() {
None (None, vec![])
} else { } else {
Some(HangMonitorRegister::init( let (sampling_profiler_control, sampling_profiler_port) =
background_hang_monitor_sender.clone(), ipc::channel().expect("ipc channel failure");
))
(
Some(HangMonitorRegister::init(
background_hang_monitor_sender.clone(),
sampling_profiler_port,
)),
vec![sampling_profiler_control],
)
}; };
let (ipc_layout_sender, ipc_layout_receiver) = let (ipc_layout_sender, ipc_layout_receiver) =
@ -640,6 +650,7 @@ where
background_hang_monitor_sender, background_hang_monitor_sender,
background_hang_monitor_receiver, background_hang_monitor_receiver,
background_monitor_register, background_monitor_register,
sampling_profiler_control: sampler_chan,
layout_sender: ipc_layout_sender, layout_sender: ipc_layout_sender,
script_receiver: script_receiver, script_receiver: script_receiver,
compositor_receiver: compositor_receiver, compositor_receiver: compositor_receiver,
@ -841,6 +852,10 @@ where
Err(e) => return self.handle_send_error(pipeline_id, e), Err(e) => return self.handle_send_error(pipeline_id, e),
}; };
if let Some(sampler_chan) = pipeline.sampler_control_chan {
self.sampling_profiler_control.push(sampler_chan);
}
if let Some(host) = host { if let Some(host) = host {
debug!( debug!(
"Adding new host entry {} for top-level browsing context {}.", "Adding new host entry {} for top-level browsing context {}.",
@ -848,11 +863,11 @@ where
); );
let _ = self let _ = self
.event_loops .event_loops
.insert(host, Rc::downgrade(&pipeline.event_loop)); .insert(host, Rc::downgrade(&pipeline.pipeline.event_loop));
} }
assert!(!self.pipelines.contains_key(&pipeline_id)); assert!(!self.pipelines.contains_key(&pipeline_id));
self.pipelines.insert(pipeline_id, pipeline); self.pipelines.insert(pipeline_id, pipeline.pipeline);
} }
/// Get an iterator for the fully active browsing contexts in a subtree. /// Get an iterator for the fully active browsing contexts in a subtree.
@ -1202,6 +1217,20 @@ where
self.forward_event(destination_pipeline_id, event); self.forward_event(destination_pipeline_id, event);
}, },
FromCompositorMsg::SetCursor(cursor) => self.handle_set_cursor_msg(cursor), FromCompositorMsg::SetCursor(cursor) => self.handle_set_cursor_msg(cursor),
FromCompositorMsg::EnableProfiler(rate) => {
for chan in &self.sampling_profiler_control {
if let Err(e) = chan.send(SamplerControlMsg::Enable(rate)) {
warn!("error communicating with sampling profiler: {}", e);
}
}
},
FromCompositorMsg::DisableProfiler => {
for chan in &self.sampling_profiler_control {
if let Err(e) = chan.send(SamplerControlMsg::Disable) {
warn!("error communicating with sampling profiler: {}", e);
}
}
},
} }
} }

View file

@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::event_loop::EventLoop; use crate::event_loop::EventLoop;
use background_hang_monitor::HangMonitorRegister;
use bluetooth_traits::BluetoothRequest; use bluetooth_traits::BluetoothRequest;
use canvas_traits::webgl::WebGLPipeline; use canvas_traits::webgl::WebGLPipeline;
use compositing::compositor_thread::Msg as CompositorMsg; use compositing::compositor_thread::Msg as CompositorMsg;
@ -18,7 +19,7 @@ use ipc_channel::Error;
use layout_traits::LayoutThreadFactory; use layout_traits::LayoutThreadFactory;
use metrics::PaintTimeMetrics; use metrics::PaintTimeMetrics;
use msg::constellation_msg::TopLevelBrowsingContextId; use msg::constellation_msg::TopLevelBrowsingContextId;
use msg::constellation_msg::{BackgroundHangMonitorRegister, HangMonitorAlert}; use msg::constellation_msg::{BackgroundHangMonitorRegister, HangMonitorAlert, SamplerControlMsg};
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId}; use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId};
use net::image_cache::ImageCacheImpl; use net::image_cache::ImageCacheImpl;
use net_traits::image_cache::ImageCache; use net_traits::image_cache::ImageCache;
@ -188,10 +189,15 @@ pub struct InitialPipelineState {
pub webvr_chan: Option<IpcSender<WebVRMsg>>, pub webvr_chan: Option<IpcSender<WebVRMsg>>,
} }
pub struct NewPipeline {
pub pipeline: Pipeline,
pub sampler_control_chan: Option<IpcSender<SamplerControlMsg>>,
}
impl Pipeline { impl Pipeline {
/// Starts a layout thread, and possibly a script thread, in /// Starts a layout thread, and possibly a script thread, in
/// a new process if requested. /// a new process if requested.
pub fn spawn<Message, LTF, STF>(state: InitialPipelineState) -> Result<Pipeline, Error> pub fn spawn<Message, LTF, STF>(state: InitialPipelineState) -> Result<NewPipeline, Error>
where where
LTF: LayoutThreadFactory<Message = Message>, LTF: LayoutThreadFactory<Message = Message>,
STF: ScriptThreadFactory<Message = Message>, STF: ScriptThreadFactory<Message = Message>,
@ -210,7 +216,7 @@ impl Pipeline {
let url = state.load_data.url.clone(); let url = state.load_data.url.clone();
let script_chan = match state.event_loop { let (script_chan, sampler_chan) = match state.event_loop {
Some(script_chan) => { Some(script_chan) => {
let new_layout_info = NewLayoutInfo { let new_layout_info = NewLayoutInfo {
parent_info: state.parent_pipeline_id, parent_info: state.parent_pipeline_id,
@ -229,7 +235,7 @@ impl Pipeline {
{ {
warn!("Sending to script during pipeline creation failed ({})", e); warn!("Sending to script during pipeline creation failed ({})", e);
} }
script_chan (script_chan, None)
}, },
None => { None => {
let (script_chan, script_port) = ipc::channel().expect("Pipeline script chan"); let (script_chan, script_port) = ipc::channel().expect("Pipeline script chan");
@ -262,7 +268,7 @@ impl Pipeline {
let (script_content_process_shutdown_chan, script_content_process_shutdown_port) = let (script_content_process_shutdown_chan, script_content_process_shutdown_port) =
ipc::channel().expect("Pipeline script content process shutdown chan"); ipc::channel().expect("Pipeline script content process shutdown chan");
let unprivileged_pipeline_content = UnprivilegedPipelineContent { let mut unprivileged_pipeline_content = UnprivilegedPipelineContent {
id: state.id, id: state.id,
browsing_context_id: state.browsing_context_id, browsing_context_id: state.browsing_context_id,
top_level_browsing_context_id: state.top_level_browsing_context_id, top_level_browsing_context_id: state.top_level_browsing_context_id,
@ -272,6 +278,7 @@ impl Pipeline {
background_hang_monitor_to_constellation_chan: state background_hang_monitor_to_constellation_chan: state
.background_hang_monitor_to_constellation_chan .background_hang_monitor_to_constellation_chan
.clone(), .clone(),
sampling_profiler_port: None,
scheduler_chan: state.scheduler_chan, scheduler_chan: state.scheduler_chan,
devtools_chan: script_to_devtools_chan, devtools_chan: script_to_devtools_chan,
bluetooth_thread: state.bluetooth_thread, bluetooth_thread: state.bluetooth_thread,
@ -302,21 +309,25 @@ impl Pipeline {
// Spawn the child process. // Spawn the child process.
// //
// Yes, that's all there is to it! // Yes, that's all there is to it!
if opts::multiprocess() { let sampler_chan = if opts::multiprocess() {
let (sampler_chan, sampler_port) = ipc::channel().expect("Sampler chan");
unprivileged_pipeline_content.sampling_profiler_port = Some(sampler_port);
let _ = unprivileged_pipeline_content.spawn_multiprocess()?; let _ = unprivileged_pipeline_content.spawn_multiprocess()?;
Some(sampler_chan)
} else { } else {
// Should not be None in single-process mode. // Should not be None in single-process mode.
let register = state let register = state
.background_monitor_register .background_monitor_register
.expect("Couldn't start content, no background monitor has been initiated"); .expect("Couldn't start content, no background monitor has been initiated");
unprivileged_pipeline_content.start_all::<Message, LTF, STF>(false, register); unprivileged_pipeline_content.start_all::<Message, LTF, STF>(false, register);
} None
};
EventLoop::new(script_chan) (EventLoop::new(script_chan), sampler_chan)
}, },
}; };
Ok(Pipeline::new( let pipeline = Pipeline::new(
state.id, state.id,
state.browsing_context_id, state.browsing_context_id,
state.top_level_browsing_context_id, state.top_level_browsing_context_id,
@ -327,7 +338,11 @@ impl Pipeline {
url, url,
state.prev_visibility, state.prev_visibility,
state.load_data, state.load_data,
)) );
Ok(NewPipeline {
pipeline,
sampler_control_chan: sampler_chan,
})
} }
/// Creates a new `Pipeline`, after the script and layout threads have been /// Creates a new `Pipeline`, after the script and layout threads have been
@ -468,6 +483,7 @@ pub struct UnprivilegedPipelineContent {
opener: Option<BrowsingContextId>, opener: Option<BrowsingContextId>,
script_to_constellation_chan: ScriptToConstellationChan, script_to_constellation_chan: ScriptToConstellationChan,
background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>, background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>,
sampling_profiler_port: Option<IpcReceiver<SamplerControlMsg>>,
layout_to_constellation_chan: IpcSender<LayoutMsg>, layout_to_constellation_chan: IpcSender<LayoutMsg>,
scheduler_chan: IpcSender<TimerSchedulerMsg>, scheduler_chan: IpcSender<TimerSchedulerMsg>,
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
@ -669,8 +685,13 @@ impl UnprivilegedPipelineContent {
} }
} }
pub fn background_hang_monitor_to_constellation_chan(&self) -> &IpcSender<HangMonitorAlert> { pub fn register_with_background_hang_monitor(&mut self) -> Box<BackgroundHangMonitorRegister> {
&self.background_hang_monitor_to_constellation_chan HangMonitorRegister::init(
self.background_hang_monitor_to_constellation_chan.clone(),
self.sampling_profiler_port
.take()
.expect("no sampling profiler?"),
)
} }
pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan { pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan {

View file

@ -490,3 +490,10 @@ pub trait BackgroundHangMonitor {
/// Unregister the component from monitor. /// Unregister the component from monitor.
fn unregister(&self); fn unregister(&self);
} }
/// Messages to control the sampling profiler.
#[derive(Deserialize, Serialize)]
pub enum SamplerControlMsg {
Enable(Duration),
Disable,
}

View file

@ -51,6 +51,7 @@ use servo_url::ServoUrl;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use style_traits::CSSPixel; use style_traits::CSSPixel;
use style_traits::SpeculativePainter; use style_traits::SpeculativePainter;
use webrender_api::{ use webrender_api::{
@ -777,6 +778,10 @@ pub enum ConstellationMsg {
ForwardEvent(PipelineId, CompositorEvent), ForwardEvent(PipelineId, CompositorEvent),
/// Requesting a change to the onscreen cursor. /// Requesting a change to the onscreen cursor.
SetCursor(Cursor), SetCursor(Cursor),
/// Enable the sampling profiler.
EnableProfiler(Duration),
/// Disable the sampling profiler.
DisableProfiler,
} }
impl fmt::Debug for ConstellationMsg { impl fmt::Debug for ConstellationMsg {
@ -804,6 +809,8 @@ impl fmt::Debug for ConstellationMsg {
SelectBrowser(..) => "SelectBrowser", SelectBrowser(..) => "SelectBrowser",
ForwardEvent(..) => "ForwardEvent", ForwardEvent(..) => "ForwardEvent",
SetCursor(..) => "SetCursor", SetCursor(..) => "SetCursor",
EnableProfiler(..) => "EnableProfiler",
DisableProfiler => "DisableProfiler",
}; };
write!(formatter, "ConstellationMsg::{}", variant) write!(formatter, "ConstellationMsg::{}", variant)
} }

View file

@ -60,7 +60,6 @@ fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
#[cfg(not(feature = "webdriver"))] #[cfg(not(feature = "webdriver"))]
fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) {} fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) {}
use background_hang_monitor::HangMonitorRegister;
use bluetooth::BluetoothThreadFactory; use bluetooth::BluetoothThreadFactory;
use bluetooth_traits::BluetoothRequest; use bluetooth_traits::BluetoothRequest;
use canvas::gl_context::GLContextFactory; use canvas::gl_context::GLContextFactory;
@ -133,6 +132,7 @@ pub struct Servo<Window: WindowMethods + 'static> {
constellation_chan: Sender<ConstellationMsg>, constellation_chan: Sender<ConstellationMsg>,
embedder_receiver: EmbedderReceiver, embedder_receiver: EmbedderReceiver,
embedder_events: Vec<(Option<BrowserId>, EmbedderMsg)>, embedder_events: Vec<(Option<BrowserId>, EmbedderMsg)>,
profiler_enabled: bool,
} }
#[derive(Clone)] #[derive(Clone)]
@ -318,6 +318,7 @@ where
constellation_chan: constellation_chan, constellation_chan: constellation_chan,
embedder_receiver: embedder_receiver, embedder_receiver: embedder_receiver,
embedder_events: Vec::new(), embedder_events: Vec::new(),
profiler_enabled: false,
} }
} }
@ -407,7 +408,15 @@ where
}, },
WindowEvent::ToggleSamplingProfiler(rate) => { WindowEvent::ToggleSamplingProfiler(rate) => {
HangMonitorRegister::toggle(rate); self.profiler_enabled = !self.profiler_enabled;
let msg = if self.profiler_enabled {
ConstellationMsg::EnableProfiler(rate)
} else {
ConstellationMsg::DisableProfiler
};
if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending profiler toggle to constellation failed ({:?}).", e);
}
}, },
WindowEvent::ToggleWebRenderDebug(option) => { WindowEvent::ToggleWebRenderDebug(option) => {
@ -714,7 +723,7 @@ pub fn run_content_process(token: String) {
.send(unprivileged_content_sender) .send(unprivileged_content_sender)
.unwrap(); .unwrap();
let unprivileged_content = unprivileged_content_receiver.recv().unwrap(); let mut unprivileged_content = unprivileged_content_receiver.recv().unwrap();
opts::set_options(unprivileged_content.opts()); opts::set_options(unprivileged_content.opts());
PREFS.extend(unprivileged_content.prefs()); PREFS.extend(unprivileged_content.prefs());
set_logger(unprivileged_content.script_to_constellation_chan().clone()); set_logger(unprivileged_content.script_to_constellation_chan().clone());
@ -724,11 +733,8 @@ pub fn run_content_process(token: String) {
create_sandbox(); create_sandbox();
} }
let background_hang_monitor_register = HangMonitorRegister::init( let background_hang_monitor_register =
unprivileged_content unprivileged_content.register_with_background_hang_monitor();
.background_hang_monitor_to_constellation_chan()
.clone(),
);
// send the required channels to the service worker manager // send the required channels to the service worker manager
let sw_senders = unprivileged_content.swmanager_senders(); let sw_senders = unprivileged_content.swmanager_senders();