mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Wire up the JS engine's memory reporting.
SpiderMonkey provides an extremely fine-grained breakdown of memory usage, but for Servo we aggregate the measurements into a small number of coarse buckets, which seems appropriate for the current level of detail provided by Servo's memory profiler. Sample output: ``` | 10.99 MiB -- pages | 7.75 MiB -- url(http://html5demos.com/worker) | 4.63 MiB -- js | 2.00 MiB -- gc-heap | 0.94 MiB -- decommitted | 0.92 MiB -- used | 0.09 MiB -- unused | 0.05 MiB -- admin | 1.44 MiB -- malloc-heap | 1.19 MiB -- non-heap | [...] | 3.24 MiB -- url(http://html5demos.com/js/worker-cruncher.js) | 3.24 MiB -- js | 1.17 MiB -- malloc-heap | 1.06 MiB -- non-heap | 1.00 MiB -- gc-heap | 0.69 MiB -- used | 0.19 MiB -- decommitted | 0.09 MiB -- unused | 0.03 MiB -- admin ``` Most of the changes are plumbing to get the script and worker tasks communicating with the memory profiler task.
This commit is contained in:
parent
ef9715203e
commit
7429b90e02
15 changed files with 177 additions and 21 deletions
|
@ -29,6 +29,7 @@ use msg::constellation_msg::PipelineId;
|
|||
use devtools_traits::DevtoolsControlChan;
|
||||
|
||||
use net_traits::{load_whole_resource, ResourceTask};
|
||||
use profile_traits::mem::{self, Reporter, ReportsChan};
|
||||
use util::task::spawn_named;
|
||||
use util::task_state;
|
||||
use util::task_state::{SCRIPT, IN_WORKER};
|
||||
|
@ -39,6 +40,7 @@ use js::jsval::UndefinedValue;
|
|||
use js::rust::Runtime;
|
||||
use url::Url;
|
||||
|
||||
use rand::random;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||
|
||||
|
@ -64,6 +66,13 @@ 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
|
||||
|
@ -105,6 +114,7 @@ pub struct DedicatedWorkerGlobalScope {
|
|||
impl DedicatedWorkerGlobalScope {
|
||||
fn new_inherited(worker_url: Url,
|
||||
id: PipelineId,
|
||||
mem_profiler_chan: mem::ProfilerChan,
|
||||
devtools_chan: Option<DevtoolsControlChan>,
|
||||
runtime: Rc<Runtime>,
|
||||
resource_task: ResourceTask,
|
||||
|
@ -115,7 +125,7 @@ impl DedicatedWorkerGlobalScope {
|
|||
DedicatedWorkerGlobalScope {
|
||||
workerglobalscope: WorkerGlobalScope::new_inherited(
|
||||
WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url,
|
||||
runtime, resource_task, devtools_chan),
|
||||
runtime, resource_task, mem_profiler_chan, devtools_chan),
|
||||
id: id,
|
||||
receiver: receiver,
|
||||
own_sender: own_sender,
|
||||
|
@ -126,6 +136,7 @@ impl DedicatedWorkerGlobalScope {
|
|||
|
||||
pub fn new(worker_url: Url,
|
||||
id: PipelineId,
|
||||
mem_profiler_chan: mem::ProfilerChan,
|
||||
devtools_chan: Option<DevtoolsControlChan>,
|
||||
runtime: Rc<Runtime>,
|
||||
resource_task: ResourceTask,
|
||||
|
@ -134,7 +145,7 @@ impl DedicatedWorkerGlobalScope {
|
|||
receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>)
|
||||
-> Root<DedicatedWorkerGlobalScope> {
|
||||
let scope = box DedicatedWorkerGlobalScope::new_inherited(
|
||||
worker_url, id, devtools_chan, runtime.clone(), resource_task,
|
||||
worker_url, id, mem_profiler_chan, devtools_chan, runtime.clone(), resource_task,
|
||||
parent_sender, own_sender, receiver);
|
||||
DedicatedWorkerGlobalScopeBinding::Wrap(runtime.cx(), scope)
|
||||
}
|
||||
|
@ -143,6 +154,7 @@ impl DedicatedWorkerGlobalScope {
|
|||
impl DedicatedWorkerGlobalScope {
|
||||
pub fn run_worker_scope(worker_url: Url,
|
||||
id: PipelineId,
|
||||
mem_profiler_chan: mem::ProfilerChan,
|
||||
devtools_chan: Option<DevtoolsControlChan>,
|
||||
worker: TrustedWorkerAddress,
|
||||
resource_task: ResourceTask,
|
||||
|
@ -171,8 +183,12 @@ impl DedicatedWorkerGlobalScope {
|
|||
let runtime = Rc::new(ScriptTask::new_rt_and_cx());
|
||||
let serialized_url = url.serialize();
|
||||
let global = DedicatedWorkerGlobalScope::new(
|
||||
url, id, devtools_chan, runtime.clone(), resource_task,
|
||||
url, id, mem_profiler_chan.clone(), devtools_chan, runtime.clone(), resource_task,
|
||||
parent_sender, own_sender, receiver);
|
||||
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
|
||||
// registration (#6631), so we instead use a random number and cross our fingers.
|
||||
let reporter_name = format!("worker-reporter-{}", random::<u64>());
|
||||
println!("reporter_name = {}", reporter_name);
|
||||
|
||||
{
|
||||
let _ar = AutoWorkerReset::new(global.r(), worker);
|
||||
|
@ -188,6 +204,12 @@ impl DedicatedWorkerGlobalScope {
|
|||
report_pending_exception(runtime.cx(), global.r().reflector().get_jsobject().get());
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
loop {
|
||||
|
@ -199,12 +221,17 @@ impl DedicatedWorkerGlobalScope {
|
|||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister this task as a memory reporter.
|
||||
let msg = mem::ProfilerMsg::UnregisterReporter(reporter_name);
|
||||
mem_profiler_chan.send(msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -218,6 +245,14 @@ 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
|
||||
}
|
||||
|
@ -263,6 +298,13 @@ impl<'a> PrivateDedicatedWorkerGlobalScopeHelpers for &'a DedicatedWorkerGlobalS
|
|||
let scope = WorkerGlobalScopeCast::from_ref(self);
|
||||
scope.handle_fire_timer(timer_id);
|
||||
}
|
||||
ScriptMsg::CollectReports(reports_chan) => {
|
||||
let scope = WorkerGlobalScopeCast::from_ref(self);
|
||||
let cx = scope.get_cx();
|
||||
let path_seg = format!("url({})", scope.get_url());
|
||||
let reports = ScriptTask::get_reports(cx, path_seg);
|
||||
reports_chan.send(reports);
|
||||
}
|
||||
_ => panic!("Unexpected message"),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue