mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 01:35:35 +00:00
servo: Merge #6629 - profile: Make the time and memory profilers run over IPC (from pcwalton:profiler-ipc); r=jdm
Uses a couple of extra threads to work around the lack of cross-process boxed trait objects. r? @nnethercote Source-Repo: https://github.com/servo/servo Source-Revision: f778e0eecf7cd8a2b870d18c3c305ff10d6b1894
This commit is contained in:
parent
54512c17f4
commit
939c609e32
@ -22,6 +22,8 @@ use gfx::paint_task::Msg as PaintMsg;
|
||||
use gfx::paint_task::PaintRequest;
|
||||
use gleam::gl::types::{GLint, GLsizei};
|
||||
use gleam::gl;
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use layers::geometry::{DevicePixel, LayerPixel};
|
||||
use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
|
||||
use layers::platform::surface::NativeDisplay;
|
||||
@ -37,7 +39,7 @@ use msg::constellation_msg::{ConstellationChan, NavigationDirection};
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
|
||||
use msg::constellation_msg::{PipelineId, WindowSizeData};
|
||||
use png;
|
||||
use profile_traits::mem;
|
||||
use profile_traits::mem::{self, Reporter, ReporterRequest};
|
||||
use profile_traits::time::{self, ProfilerCategory, profile};
|
||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg, ScriptControlChan};
|
||||
use std::collections::HashMap;
|
||||
@ -257,7 +259,13 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||
-> IOCompositor<Window> {
|
||||
|
||||
// Register this thread as a memory reporter, via its own channel.
|
||||
let reporter = box CompositorMemoryReporter(sender.clone_compositor_proxy());
|
||||
let (reporter_sender, reporter_receiver) = ipc::channel().unwrap();
|
||||
let compositor_proxy_for_memory_reporter = sender.clone_compositor_proxy();
|
||||
ROUTER.add_route(reporter_receiver.to_opaque(), box move |reporter_request| {
|
||||
let reporter_request: ReporterRequest = reporter_request.to().unwrap();
|
||||
compositor_proxy_for_memory_reporter.send(Msg::CollectMemoryReports(reporter_request.reports_channel));
|
||||
});
|
||||
let reporter = Reporter(reporter_sender);
|
||||
mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(reporter_name(), reporter));
|
||||
|
||||
let window_size = window.framebuffer_size();
|
||||
@ -1723,19 +1731,3 @@ pub enum CompositingReason {
|
||||
Zoom,
|
||||
}
|
||||
|
||||
struct CompositorMemoryReporter(Box<CompositorProxy+'static+Send>);
|
||||
|
||||
impl CompositorMemoryReporter {
|
||||
pub fn send(&self, message: Msg) {
|
||||
let CompositorMemoryReporter(ref proxy) = *self;
|
||||
proxy.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
impl mem::Reporter for CompositorMemoryReporter {
|
||||
fn collect_reports(&self, reports_chan: mem::ReportsChan) -> bool {
|
||||
// FIXME(mrobinson): The port should probably return the success of the message here.
|
||||
self.send(Msg::CollectMemoryReports(reports_chan));
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ git = "https://github.com/servo/skia"
|
||||
[dependencies.script_traits]
|
||||
path = "../script_traits"
|
||||
|
||||
[dependencies.ipc-channel]
|
||||
git = "https://github.com/pcwalton/ipc-channel"
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
fnv = "1.0"
|
||||
|
@ -24,6 +24,7 @@ extern crate azure;
|
||||
#[macro_use] extern crate bitflags;
|
||||
extern crate fnv;
|
||||
extern crate euclid;
|
||||
extern crate ipc_channel;
|
||||
extern crate layers;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
|
@ -15,6 +15,8 @@ use euclid::Matrix4;
|
||||
use euclid::point::Point2D;
|
||||
use euclid::rect::Rect;
|
||||
use euclid::size::Size2D;
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use layers::platform::surface::{NativeDisplay, NativeSurface};
|
||||
use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
|
||||
use canvas_traits::CanvasMsg;
|
||||
@ -23,7 +25,7 @@ use msg::compositor_msg::{LayerProperties, PaintListener, ScrollPolicy};
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
|
||||
use msg::constellation_msg::PipelineExitType;
|
||||
use profile_traits::mem::{self, Reporter, ReportsChan};
|
||||
use profile_traits::mem::{self, Reporter, ReporterRequest, ReportsChan};
|
||||
use profile_traits::time::{self, profile};
|
||||
use rand::{self, Rng};
|
||||
use std::borrow::ToOwned;
|
||||
@ -97,14 +99,6 @@ impl PaintChan {
|
||||
}
|
||||
}
|
||||
|
||||
impl Reporter for PaintChan {
|
||||
// Just injects an appropriate event into the paint task's queue.
|
||||
fn collect_reports(&self, reports_chan: ReportsChan) -> bool {
|
||||
let PaintChan(ref c) = *self;
|
||||
c.send(Msg::CollectReports(reports_chan)).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PaintTask<C> {
|
||||
id: PipelineId,
|
||||
_url: Url,
|
||||
@ -178,11 +172,20 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
||||
canvas_map: HashMap::new()
|
||||
};
|
||||
|
||||
// Register this thread as a memory reporter, via its own channel.
|
||||
let reporter = box chan.clone();
|
||||
// Register the memory reporter.
|
||||
let reporter_name = format!("paint-reporter-{}", id.0);
|
||||
let msg = mem::ProfilerMsg::RegisterReporter(reporter_name.clone(), reporter);
|
||||
mem_profiler_chan.send(msg);
|
||||
let (reporter_sender, reporter_receiver) =
|
||||
ipc::channel::<ReporterRequest>().unwrap();
|
||||
let paint_chan_for_reporter = chan.clone();
|
||||
ROUTER.add_route(reporter_receiver.to_opaque(), box move |message| {
|
||||
// Just injects an appropriate event into the paint task's queue.
|
||||
let request: ReporterRequest = message.to().unwrap();
|
||||
paint_chan_for_reporter.0.send(Msg::CollectReports(request.reports_channel))
|
||||
.unwrap();
|
||||
});
|
||||
mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(
|
||||
reporter_name.clone(),
|
||||
Reporter(reporter_sender)));
|
||||
|
||||
paint_task.start();
|
||||
|
||||
@ -260,8 +263,9 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
||||
Msg::PaintPermissionRevoked => {
|
||||
self.paint_permission = false;
|
||||
}
|
||||
Msg::CollectReports(_) => {
|
||||
Msg::CollectReports(ref channel) => {
|
||||
// FIXME(njn): should eventually measure the paint task.
|
||||
channel.send(Vec::new())
|
||||
}
|
||||
Msg::Exit(response_channel, _) => {
|
||||
// Ask the compositor to remove any layers it is holding for this paint task.
|
||||
|
@ -39,13 +39,14 @@ use gfx::display_list::StackingContext;
|
||||
use gfx::font_cache_task::FontCacheTask;
|
||||
use gfx::paint_task::Msg as PaintMsg;
|
||||
use gfx::paint_task::{PaintChan, PaintLayer};
|
||||
use ipc_channel::ipc::IpcReceiver;
|
||||
use ipc_channel::ipc::{self, IpcReceiver};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use layout_traits::LayoutTaskFactory;
|
||||
use log;
|
||||
use msg::compositor_msg::{Epoch, ScrollPolicy, LayerId};
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId};
|
||||
use profile_traits::mem::{self, Report, ReportsChan};
|
||||
use profile_traits::mem::{self, Report, Reporter, ReporterRequest, ReportsChan};
|
||||
use profile_traits::time::{self, ProfilerMetadata, profile};
|
||||
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
|
||||
use net_traits::{load_bytes_iter, PendingAsyncLoad};
|
||||
@ -242,11 +243,20 @@ impl LayoutTaskFactory for LayoutTask {
|
||||
time_profiler_chan,
|
||||
mem_profiler_chan.clone());
|
||||
|
||||
// Register this thread as a memory reporter, via its own channel.
|
||||
let reporter = box layout_chan.clone();
|
||||
// Create a memory reporter thread.
|
||||
let reporter_name = format!("layout-reporter-{}", id.0);
|
||||
let msg = mem::ProfilerMsg::RegisterReporter(reporter_name.clone(), reporter);
|
||||
mem_profiler_chan.send(msg);
|
||||
let (reporter_sender, reporter_receiver) =
|
||||
ipc::channel::<ReporterRequest>().unwrap();
|
||||
let layout_chan_for_reporter = layout_chan.clone();
|
||||
ROUTER.add_route(reporter_receiver.to_opaque(), box move |message| {
|
||||
// Just injects an appropriate event into the layout task's queue.
|
||||
let request: ReporterRequest = message.to().unwrap();
|
||||
layout_chan_for_reporter.0.send(Msg::CollectReports(request.reports_channel))
|
||||
.unwrap();
|
||||
});
|
||||
mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(
|
||||
reporter_name.clone(),
|
||||
Reporter(reporter_sender)));
|
||||
|
||||
layout.start();
|
||||
|
||||
|
@ -13,6 +13,9 @@ path = "../profile_traits"
|
||||
[dependencies.util]
|
||||
path = "../util"
|
||||
|
||||
[dependencies.ipc-channel]
|
||||
git = "https://github.com/pcwalton/ipc-channel"
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
libc = "0.1"
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
extern crate ipc_channel;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate profile_traits;
|
||||
|
@ -4,26 +4,26 @@
|
||||
|
||||
//! Memory profiling functions.
|
||||
|
||||
use profile_traits::mem::{ProfilerChan, ProfilerMsg, Reporter, ReportsChan};
|
||||
use self::system_reporter::SystemReporter;
|
||||
use ipc_channel::ipc::{self, IpcReceiver};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use profile_traits::mem::{ProfilerChan, ProfilerMsg, Reporter, ReporterRequest, ReportsChan};
|
||||
use std::borrow::ToOwned;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::thread::sleep_ms;
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
use util::task::spawn_named;
|
||||
|
||||
pub struct Profiler {
|
||||
/// The port through which messages are received.
|
||||
pub port: Receiver<ProfilerMsg>,
|
||||
pub port: IpcReceiver<ProfilerMsg>,
|
||||
|
||||
/// Registered memory reporters.
|
||||
reporters: HashMap<String, Box<Reporter + Send>>,
|
||||
reporters: HashMap<String, Reporter>,
|
||||
}
|
||||
|
||||
impl Profiler {
|
||||
pub fn create(period: Option<f64>) -> ProfilerChan {
|
||||
let (chan, port) = channel();
|
||||
let (chan, port) = ipc::channel().unwrap();
|
||||
|
||||
// Create the timer thread if a period was provided.
|
||||
if let Some(period) = period {
|
||||
@ -48,16 +48,21 @@ impl Profiler {
|
||||
|
||||
let mem_profiler_chan = ProfilerChan(chan);
|
||||
|
||||
// Register the system memory reporter, which will run on the memory profiler's own thread.
|
||||
// It never needs to be unregistered, because as long as the memory profiler is running the
|
||||
// system memory reporter can make measurements.
|
||||
let system_reporter = box SystemReporter;
|
||||
mem_profiler_chan.send(ProfilerMsg::RegisterReporter("system".to_owned(), system_reporter));
|
||||
// Register the system memory reporter, which will run on its own thread. It never needs to
|
||||
// be unregistered, because as long as the memory profiler is running the system memory
|
||||
// reporter can make measurements.
|
||||
let (system_reporter_sender, system_reporter_receiver) = ipc::channel().unwrap();
|
||||
ROUTER.add_route(system_reporter_receiver.to_opaque(), box |message| {
|
||||
let request: ReporterRequest = message.to().unwrap();
|
||||
system_reporter::collect_reports(request)
|
||||
});
|
||||
mem_profiler_chan.send(ProfilerMsg::RegisterReporter("system".to_owned(),
|
||||
Reporter(system_reporter_sender)));
|
||||
|
||||
mem_profiler_chan
|
||||
}
|
||||
|
||||
pub fn new(port: Receiver<ProfilerMsg>) -> Profiler {
|
||||
pub fn new(port: IpcReceiver<ProfilerMsg>) -> Profiler {
|
||||
Profiler {
|
||||
port: port,
|
||||
reporters: HashMap::new(),
|
||||
@ -119,12 +124,11 @@ impl Profiler {
|
||||
// If anything goes wrong with a reporter, we just skip it.
|
||||
let mut forest = ReportsForest::new();
|
||||
for reporter in self.reporters.values() {
|
||||
let (chan, port) = channel();
|
||||
if reporter.collect_reports(ReportsChan(chan)) {
|
||||
if let Ok(reports) = port.recv() {
|
||||
for report in reports.iter() {
|
||||
forest.insert(&report.path, report.size);
|
||||
}
|
||||
let (chan, port) = ipc::channel().unwrap();
|
||||
reporter.collect_reports(ReportsChan(chan));
|
||||
if let Ok(reports) = port.recv() {
|
||||
for report in reports.iter() {
|
||||
forest.insert(&report.path, report.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -297,7 +301,7 @@ impl ReportsForest {
|
||||
|
||||
mod system_reporter {
|
||||
use libc::{c_char, c_int, c_void, size_t};
|
||||
use profile_traits::mem::{Report, Reporter, ReportsChan};
|
||||
use profile_traits::mem::{Report, ReporterRequest};
|
||||
use std::borrow::ToOwned;
|
||||
use std::ffi::CString;
|
||||
use std::mem::size_of;
|
||||
@ -306,51 +310,46 @@ mod system_reporter {
|
||||
use task_info::task_basic_info::{virtual_size, resident_size};
|
||||
|
||||
/// Collects global measurements from the OS and heap allocators.
|
||||
pub struct SystemReporter;
|
||||
|
||||
impl Reporter for SystemReporter {
|
||||
fn collect_reports(&self, reports_chan: ReportsChan) -> bool {
|
||||
let mut reports = vec![];
|
||||
{
|
||||
let mut report = |path, size| {
|
||||
if let Some(size) = size {
|
||||
reports.push(Report { path: path, size: size });
|
||||
}
|
||||
};
|
||||
|
||||
// Virtual and physical memory usage, as reported by the OS.
|
||||
report(path!["vsize"], get_vsize());
|
||||
report(path!["resident"], get_resident());
|
||||
|
||||
// Memory segments, as reported by the OS.
|
||||
for seg in get_resident_segments().iter() {
|
||||
report(path!["resident-according-to-smaps", seg.0], Some(seg.1));
|
||||
pub fn collect_reports(request: ReporterRequest) {
|
||||
let mut reports = vec![];
|
||||
{
|
||||
let mut report = |path, size| {
|
||||
if let Some(size) = size {
|
||||
reports.push(Report { path: path, size: size });
|
||||
}
|
||||
};
|
||||
|
||||
// Total number of bytes allocated by the application on the system
|
||||
// heap.
|
||||
report(path!["system-heap-allocated"], get_system_heap_allocated());
|
||||
// Virtual and physical memory usage, as reported by the OS.
|
||||
report(path!["vsize"], get_vsize());
|
||||
report(path!["resident"], get_resident());
|
||||
|
||||
// The descriptions of the following jemalloc measurements are taken
|
||||
// directly from the jemalloc documentation.
|
||||
|
||||
// "Total number of bytes allocated by the application."
|
||||
report(path!["jemalloc-heap-allocated"], get_jemalloc_stat("stats.allocated"));
|
||||
|
||||
// "Total number of bytes in active pages allocated by the application.
|
||||
// This is a multiple of the page size, and greater than or equal to
|
||||
// |stats.allocated|."
|
||||
report(path!["jemalloc-heap-active"], get_jemalloc_stat("stats.active"));
|
||||
|
||||
// "Total number of bytes in chunks mapped on behalf of the application.
|
||||
// This is a multiple of the chunk size, and is at least as large as
|
||||
// |stats.active|. This does not include inactive chunks."
|
||||
report(path!["jemalloc-heap-mapped"], get_jemalloc_stat("stats.mapped"));
|
||||
// Memory segments, as reported by the OS.
|
||||
for seg in get_resident_segments().iter() {
|
||||
report(path!["resident-according-to-smaps", seg.0], Some(seg.1));
|
||||
}
|
||||
reports_chan.send(reports);
|
||||
|
||||
true
|
||||
// Total number of bytes allocated by the application on the system
|
||||
// heap.
|
||||
report(path!["system-heap-allocated"], get_system_heap_allocated());
|
||||
|
||||
// The descriptions of the following jemalloc measurements are taken
|
||||
// directly from the jemalloc documentation.
|
||||
|
||||
// "Total number of bytes allocated by the application."
|
||||
report(path!["jemalloc-heap-allocated"], get_jemalloc_stat("stats.allocated"));
|
||||
|
||||
// "Total number of bytes in active pages allocated by the application.
|
||||
// This is a multiple of the page size, and greater than or equal to
|
||||
// |stats.allocated|."
|
||||
report(path!["jemalloc-heap-active"], get_jemalloc_stat("stats.active"));
|
||||
|
||||
// "Total number of bytes in chunks mapped on behalf of the application.
|
||||
// This is a multiple of the chunk size, and is at least as large as
|
||||
// |stats.active|. This does not include inactive chunks."
|
||||
report(path!["jemalloc-heap-mapped"], get_jemalloc_stat("stats.mapped"));
|
||||
}
|
||||
|
||||
request.reports_channel.send(reports);
|
||||
}
|
||||
|
||||
#[cfg(target_os="linux")]
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
//! Timing functions.
|
||||
|
||||
use ipc_channel::ipc::{self, IpcReceiver};
|
||||
use profile_traits::time::{ProfilerCategory, ProfilerChan, ProfilerMsg, TimerMetadata};
|
||||
use std::borrow::ToOwned;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
use std::f64;
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
use std::thread::sleep_ms;
|
||||
use std_time::precise_time_ns;
|
||||
use util::task::spawn_named;
|
||||
@ -86,14 +86,14 @@ type ProfilerBuckets = BTreeMap<(ProfilerCategory, Option<TimerMetadata>), Vec<f
|
||||
|
||||
// back end of the profiler that handles data aggregation and performance metrics
|
||||
pub struct Profiler {
|
||||
pub port: Receiver<ProfilerMsg>,
|
||||
pub port: IpcReceiver<ProfilerMsg>,
|
||||
buckets: ProfilerBuckets,
|
||||
pub last_msg: Option<ProfilerMsg>,
|
||||
}
|
||||
|
||||
impl Profiler {
|
||||
pub fn create(period: Option<f64>) -> ProfilerChan {
|
||||
let (chan, port) = channel();
|
||||
let (chan, port) = ipc::channel().unwrap();
|
||||
match period {
|
||||
Some(period) => {
|
||||
let period = (period * 1000.) as u32;
|
||||
@ -128,7 +128,7 @@ impl Profiler {
|
||||
ProfilerChan(chan)
|
||||
}
|
||||
|
||||
pub fn new(port: Receiver<ProfilerMsg>) -> Profiler {
|
||||
pub fn new(port: IpcReceiver<ProfilerMsg>) -> Profiler {
|
||||
Profiler {
|
||||
port: port,
|
||||
buckets: BTreeMap::new(),
|
||||
|
@ -7,7 +7,12 @@ authors = ["The Servo Project Developers"]
|
||||
name = "profile_traits"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies.ipc-channel]
|
||||
git = "https://github.com/pcwalton/ipc-channel"
|
||||
|
||||
[dependencies]
|
||||
serde = "0.4"
|
||||
serde_macros = "0.4"
|
||||
time = "0.1.12"
|
||||
url = "0.2.36"
|
||||
|
||||
|
@ -6,5 +6,12 @@
|
||||
//! rest of Servo. These APIs are here instead of in `profile` so that these
|
||||
//! modules won't have to depend on `profile`.
|
||||
|
||||
#![feature(custom_derive, plugin)]
|
||||
#![plugin(serde_macros)]
|
||||
|
||||
extern crate ipc_channel;
|
||||
extern crate serde;
|
||||
|
||||
pub mod mem;
|
||||
pub mod time;
|
||||
|
||||
|
@ -6,15 +6,15 @@
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::sync::mpsc::Sender;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
|
||||
/// Front-end representation of the profiler used to communicate with the
|
||||
/// profiler.
|
||||
#[derive(Clone)]
|
||||
pub struct ProfilerChan(pub Sender<ProfilerMsg>);
|
||||
pub struct ProfilerChan(pub IpcSender<ProfilerMsg>);
|
||||
|
||||
impl ProfilerChan {
|
||||
/// Send `msg` on this `Sender`.
|
||||
/// Send `msg` on this `IpcSender`.
|
||||
///
|
||||
/// Panics if the send fails.
|
||||
pub fn send(&self, msg: ProfilerMsg) {
|
||||
@ -24,6 +24,7 @@ impl ProfilerChan {
|
||||
}
|
||||
|
||||
/// A single memory-related measurement.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Report {
|
||||
/// The identifying path for this report.
|
||||
pub path: Vec<String>,
|
||||
@ -33,11 +34,11 @@ pub struct Report {
|
||||
}
|
||||
|
||||
/// A channel through which memory reports can be sent.
|
||||
#[derive(Clone)]
|
||||
pub struct ReportsChan(pub Sender<Vec<Report>>);
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct ReportsChan(pub IpcSender<Vec<Report>>);
|
||||
|
||||
impl ReportsChan {
|
||||
/// Send `report` on this `Sender`.
|
||||
/// Send `report` on this `IpcSender`.
|
||||
///
|
||||
/// Panics if the send fails.
|
||||
pub fn send(&self, report: Vec<Report>) {
|
||||
@ -46,13 +47,30 @@ impl ReportsChan {
|
||||
}
|
||||
}
|
||||
|
||||
/// A memory reporter is capable of measuring some data structure of interest. Because it needs to
|
||||
/// be passed to and registered with the Profiler, it's typically a "small" (i.e. easily cloneable)
|
||||
/// value that provides access to a "large" data structure, e.g. a channel that can inject a
|
||||
/// request for measurements into the event queue associated with the "large" data structure.
|
||||
pub trait Reporter {
|
||||
/// The protocol used to send reporter requests.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ReporterRequest {
|
||||
/// The channel on which reports are to be sent.
|
||||
pub reports_channel: ReportsChan,
|
||||
}
|
||||
|
||||
/// A memory reporter is capable of measuring some data structure of interest. It's structured as
|
||||
/// an IPC sender that a `ReporterRequest` in transmitted over. `ReporterRequest` objects in turn
|
||||
/// encapsulate the channel on which the memory profiling information is to be sent.
|
||||
///
|
||||
/// In many cases, clients construct `Reporter` objects by creating an IPC sender/receiver pair and
|
||||
/// registering the receiving end with the router so that messages from the memory profiler end up
|
||||
/// injected into the client's event loop.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Reporter(pub IpcSender<ReporterRequest>);
|
||||
|
||||
impl Reporter {
|
||||
/// Collect one or more memory reports. Returns true on success, and false on failure.
|
||||
fn collect_reports(&self, reports_chan: ReportsChan) -> bool;
|
||||
pub fn collect_reports(&self, reports_chan: ReportsChan) {
|
||||
self.0.send(ReporterRequest {
|
||||
reports_channel: reports_chan,
|
||||
}).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// An easy way to build a path for a report.
|
||||
@ -65,11 +83,12 @@ macro_rules! path {
|
||||
}
|
||||
|
||||
/// Messages that can be sent to the memory profiler thread.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum ProfilerMsg {
|
||||
/// Register a Reporter with the memory profiler. The String is only used to identify the
|
||||
/// reporter so it can be unregistered later. The String must be distinct from that used by any
|
||||
/// other registered reporter otherwise a panic will occur.
|
||||
RegisterReporter(String, Box<Reporter + Send>),
|
||||
RegisterReporter(String, Reporter),
|
||||
|
||||
/// Unregister a Reporter with the memory profiler. The String must match the name given when
|
||||
/// the reporter was registered. If the String does not match the name of a registered reporter
|
||||
@ -82,3 +101,4 @@ pub enum ProfilerMsg {
|
||||
/// Tells the memory profiler to shut down.
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
@ -5,19 +5,19 @@
|
||||
extern crate time as std_time;
|
||||
extern crate url;
|
||||
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use self::std_time::precise_time_ns;
|
||||
use self::url::Url;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
#[derive(PartialEq, Clone, PartialOrd, Eq, Ord)]
|
||||
#[derive(PartialEq, Clone, PartialOrd, Eq, Ord, Deserialize, Serialize)]
|
||||
pub struct TimerMetadata {
|
||||
pub url: String,
|
||||
pub iframe: bool,
|
||||
pub incremental: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProfilerChan(pub Sender<ProfilerMsg>);
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct ProfilerChan(pub IpcSender<ProfilerMsg>);
|
||||
|
||||
impl ProfilerChan {
|
||||
pub fn send(&self, msg: ProfilerMsg) {
|
||||
@ -26,7 +26,7 @@ impl ProfilerChan {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub enum ProfilerMsg {
|
||||
/// Normal message used for reporting time
|
||||
Time((ProfilerCategory, Option<TimerMetadata>), f64),
|
||||
@ -37,7 +37,7 @@ pub enum ProfilerMsg {
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(PartialEq, Clone, PartialOrd, Eq, Ord)]
|
||||
#[derive(PartialEq, Clone, PartialOrd, Eq, Ord, Deserialize, Serialize)]
|
||||
pub enum ProfilerCategory {
|
||||
Compositing,
|
||||
LayoutPerform,
|
||||
|
@ -29,11 +29,13 @@ use msg::constellation_msg::PipelineId;
|
||||
use devtools_traits::DevtoolsControlChan;
|
||||
|
||||
use net_traits::{load_whole_resource, ResourceTask};
|
||||
use profile_traits::mem::{self, Reporter, ReportsChan};
|
||||
use profile_traits::mem::{self, Reporter, ReporterRequest};
|
||||
use util::task::spawn_named;
|
||||
use util::task_state;
|
||||
use util::task_state::{SCRIPT, IN_WORKER};
|
||||
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::{JSContext, RootedValue, HandleValue};
|
||||
use js::jsapi::{JSAutoRequest, JSAutoCompartment};
|
||||
use js::jsval::UndefinedValue;
|
||||
@ -66,13 +68,6 @@ impl ScriptChan for SendableWorkerScriptChan {
|
||||
}
|
||||
}
|
||||
|
||||
impl Reporter for SendableWorkerScriptChan {
|
||||
// Just injects an appropriate event into the worker task's queue.
|
||||
fn collect_reports(&self, reports_chan: ReportsChan) -> bool {
|
||||
self.send(ScriptMsg::CollectReports(reports_chan)).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular
|
||||
/// value for the duration of this object's lifetime. This ensures that the related Worker
|
||||
/// object only lives as long as necessary (ie. while events are being executed), while
|
||||
@ -182,6 +177,7 @@ impl DedicatedWorkerGlobalScope {
|
||||
|
||||
let runtime = Rc::new(ScriptTask::new_rt_and_cx());
|
||||
let serialized_url = url.serialize();
|
||||
let parent_sender_for_reporter = parent_sender.clone();
|
||||
let global = DedicatedWorkerGlobalScope::new(
|
||||
url, id, mem_profiler_chan.clone(), devtools_chan, runtime.clone(), resource_task,
|
||||
parent_sender, own_sender, receiver);
|
||||
@ -206,9 +202,16 @@ impl DedicatedWorkerGlobalScope {
|
||||
|
||||
// Register this task as a memory reporter. This needs to be done within the
|
||||
// scope of `_ar` otherwise script_chan_as_reporter() will panic.
|
||||
let reporter = global.script_chan_as_reporter();
|
||||
let msg = mem::ProfilerMsg::RegisterReporter(reporter_name.clone(), reporter);
|
||||
mem_profiler_chan.send(msg);
|
||||
let (reporter_sender, reporter_receiver) = ipc::channel().unwrap();
|
||||
ROUTER.add_route(reporter_receiver.to_opaque(), box move |reporter_request| {
|
||||
// Just injects an appropriate event into the worker task's queue.
|
||||
let reporter_request: ReporterRequest = reporter_request.to().unwrap();
|
||||
parent_sender_for_reporter.send(ScriptMsg::CollectReports(
|
||||
reporter_request.reports_channel)).unwrap()
|
||||
});
|
||||
mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(
|
||||
reporter_name.clone(),
|
||||
Reporter(reporter_sender)));
|
||||
}
|
||||
|
||||
loop {
|
||||
@ -230,7 +233,6 @@ impl DedicatedWorkerGlobalScope {
|
||||
|
||||
pub trait DedicatedWorkerGlobalScopeHelpers {
|
||||
fn script_chan(self) -> Box<ScriptChan+Send>;
|
||||
fn script_chan_as_reporter(self) -> Box<Reporter+Send>;
|
||||
fn pipeline(self) -> PipelineId;
|
||||
fn new_script_pair(self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>);
|
||||
fn process_event(self, msg: ScriptMsg);
|
||||
@ -244,14 +246,6 @@ impl<'a> DedicatedWorkerGlobalScopeHelpers for &'a DedicatedWorkerGlobalScope {
|
||||
}
|
||||
}
|
||||
|
||||
fn script_chan_as_reporter(self) -> Box<Reporter+Send> {
|
||||
box SendableWorkerScriptChan {
|
||||
sender: self.own_sender.clone(),
|
||||
worker: self.worker.borrow().as_ref().unwrap().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn pipeline(self) -> PipelineId {
|
||||
self.id
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ use msg::constellation_msg::{WindowSizeData};
|
||||
use msg::compositor_msg::Epoch;
|
||||
use net_traits::image_cache_task::ImageCacheTask;
|
||||
use net_traits::PendingAsyncLoad;
|
||||
use profile_traits::mem::{Reporter, ReportsChan};
|
||||
use profile_traits::mem::ReportsChan;
|
||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg, ScriptControlChan};
|
||||
use script_traits::{OpaqueScriptLayoutChannel, StylesheetLoadResponder, UntrustedNodeAddress};
|
||||
use std::any::Any;
|
||||
@ -159,14 +159,6 @@ impl LayoutChan {
|
||||
}
|
||||
}
|
||||
|
||||
impl Reporter for LayoutChan {
|
||||
// Just injects an appropriate event into the layout task's queue.
|
||||
fn collect_reports(&self, reports_chan: ReportsChan) -> bool {
|
||||
let LayoutChan(ref c) = *self;
|
||||
c.send(Msg::CollectReports(reports_chan)).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait to manage opaque references to script<->layout channels without needing
|
||||
/// to expose the message type to crates that don't need to know about them.
|
||||
pub trait ScriptLayoutChan {
|
||||
|
@ -70,7 +70,7 @@ use net_traits::{ResourceTask, LoadConsumer, ControlMsg, Metadata};
|
||||
use net_traits::LoadData as NetLoadData;
|
||||
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult};
|
||||
use net_traits::storage_task::StorageTask;
|
||||
use profile_traits::mem::{self, Report, Reporter, ReportsChan};
|
||||
use profile_traits::mem::{self, Report, Reporter, ReporterRequest, ReportsChan};
|
||||
use string_cache::Atom;
|
||||
use util::str::DOMString;
|
||||
use util::task::spawn_named_with_send_on_failure;
|
||||
@ -79,6 +79,8 @@ use util::task_state;
|
||||
use euclid::Rect;
|
||||
use euclid::point::Point2D;
|
||||
use hyper::header::{LastModified, Headers};
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::glue::CollectServoSizes;
|
||||
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_AddExtraGCRootsTracer, DisableIncrementalGC};
|
||||
use js::jsapi::{JSContext, JSRuntime, JSTracer};
|
||||
@ -252,18 +254,6 @@ impl NonWorkerScriptChan {
|
||||
let (chan, port) = channel();
|
||||
(port, box NonWorkerScriptChan(chan))
|
||||
}
|
||||
|
||||
fn clone_as_reporter(&self) -> Box<Reporter+Send> {
|
||||
let NonWorkerScriptChan(ref chan) = *self;
|
||||
box NonWorkerScriptChan((*chan).clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Reporter for NonWorkerScriptChan {
|
||||
// Just injects an appropriate event into the script task's queue.
|
||||
fn collect_reports(&self, reports_chan: ReportsChan) -> bool {
|
||||
self.send(ScriptMsg::CollectReports(reports_chan)).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StackRootTLS;
|
||||
@ -420,7 +410,7 @@ impl ScriptTaskFactory for ScriptTask {
|
||||
let roots = RootCollection::new();
|
||||
let _stack_roots_tls = StackRootTLS::new(&roots);
|
||||
let chan = NonWorkerScriptChan(script_chan);
|
||||
let reporter = chan.clone_as_reporter();
|
||||
let channel_for_reporter = chan.clone();
|
||||
let script_task = ScriptTask::new(compositor,
|
||||
script_port,
|
||||
chan,
|
||||
@ -445,6 +435,14 @@ impl ScriptTaskFactory for ScriptTask {
|
||||
|
||||
// Register this task as a memory reporter.
|
||||
let reporter_name = format!("script-reporter-{}", id.0);
|
||||
let (reporter_sender, reporter_receiver) = ipc::channel().unwrap();
|
||||
ROUTER.add_route(reporter_receiver.to_opaque(), box move |reporter_request| {
|
||||
// Just injects an appropriate event into the worker task's queue.
|
||||
let reporter_request: ReporterRequest = reporter_request.to().unwrap();
|
||||
channel_for_reporter.send(ScriptMsg::CollectReports(
|
||||
reporter_request.reports_channel)).unwrap()
|
||||
});
|
||||
let reporter = Reporter(reporter_sender);
|
||||
let msg = mem::ProfilerMsg::RegisterReporter(reporter_name.clone(), reporter);
|
||||
mem_profiler_chan.send(msg);
|
||||
|
||||
|
9
servo/components/servo/Cargo.lock
generated
9
servo/components/servo/Cargo.lock
generated
@ -437,6 +437,7 @@ dependencies = [
|
||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||
"gfx_traits 0.0.1",
|
||||
"harfbuzz 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1051,6 +1052,7 @@ source = "git+https://github.com/servo/rust-png#3c3105672622c76fbb079a96384f78e4
|
||||
name = "profile"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"profile_traits 0.0.1",
|
||||
@ -1064,6 +1066,9 @@ dependencies = [
|
||||
name = "profile_traits"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1223,7 +1228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_codegen"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aster 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1236,7 +1241,7 @@ name = "serde_macros"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
9
servo/ports/cef/Cargo.lock
generated
9
servo/ports/cef/Cargo.lock
generated
@ -436,6 +436,7 @@ dependencies = [
|
||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||
"gfx_traits 0.0.1",
|
||||
"harfbuzz 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1030,6 +1031,7 @@ source = "git+https://github.com/servo/rust-png#653902184ce95d2dc44cd4674c8b273f
|
||||
name = "profile"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"profile_traits 0.0.1",
|
||||
@ -1043,6 +1045,9 @@ dependencies = [
|
||||
name = "profile_traits"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1194,7 +1199,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_codegen"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aster 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1207,7 +1212,7 @@ name = "serde_macros"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
9
servo/ports/gonk/Cargo.lock
generated
9
servo/ports/gonk/Cargo.lock
generated
@ -415,6 +415,7 @@ dependencies = [
|
||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||
"gfx_traits 0.0.1",
|
||||
"harfbuzz 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -938,6 +939,7 @@ source = "git+https://github.com/servo/rust-png#3c3105672622c76fbb079a96384f78e4
|
||||
name = "profile"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"profile_traits 0.0.1",
|
||||
@ -951,6 +953,9 @@ dependencies = [
|
||||
name = "profile_traits"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||
"serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1102,7 +1107,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_codegen"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aster 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1115,7 +1120,7 @@ name = "serde_macros"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
Loading…
Reference in New Issue
Block a user