servo: Merge #2720 - Add a basic memory profiler, invoked with -m. r=pcwalton (from nnethercote:memprof)

Source-Repo: https://github.com/servo/servo
Source-Revision: 491cc03c3a182d0bbc77123e5bc5a9995a4f8f78
This commit is contained in:
Nicholas Nethercote 2014-06-27 10:17:59 +10:00
Родитель f9030541e2
Коммит 7eeecb11b3
16 изменённых файлов: 311 добавлений и 119 удалений

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

@ -51,7 +51,8 @@ pub extern "C" fn cef_run_message_loop() {
cpu_painting: false,
tile_size: 512,
device_pixels_per_px: None,
profiler_period: None,
time_profiler_period: None,
memory_profiler_period: None,
layout_threads: 1,
//layout_threads: cmp::max(rt::default_sched_threads() * 3 / 4, 1),
exit_after_load: false,

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

@ -11,7 +11,7 @@ use platform::font_context::FontContextHandle;
use azure::azure_hl::BackendType;
use collections::hashmap::HashMap;
use servo_util::cache::{Cache, LRUCache};
use servo_util::time::ProfilerChan;
use servo_util::time::TimeProfilerChan;
use std::rc::Rc;
use std::cell::RefCell;
@ -25,8 +25,8 @@ pub struct FontContextInfo {
/// Whether we need a font list.
pub needs_font_list: bool,
/// A channel up to the profiler.
pub profiler_chan: ProfilerChan,
/// A channel up to the time profiler.
pub time_profiler_chan: TimeProfilerChan,
}
pub trait FontContextHandleMethods {
@ -40,14 +40,14 @@ pub struct FontContext {
pub handle: FontContextHandle,
pub backend: BackendType,
pub generic_fonts: HashMap<String,String>,
pub profiler_chan: ProfilerChan,
pub time_profiler_chan: TimeProfilerChan,
}
impl FontContext {
pub fn new(info: FontContextInfo) -> FontContext {
let handle = FontContextHandle::new();
let font_list = if info.needs_font_list {
Some(FontList::new(&handle, info.profiler_chan.clone()))
Some(FontList::new(&handle, info.time_profiler_chan.clone()))
} else {
None
};
@ -67,7 +67,7 @@ impl FontContext {
handle: handle,
backend: info.backend,
generic_fonts: generic_fonts,
profiler_chan: info.profiler_chan.clone(),
time_profiler_chan: info.time_profiler_chan.clone(),
}
}

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

@ -10,7 +10,7 @@ use platform::font_context::FontContextHandle;
use platform::font_list::FontListHandle;
use style::computed_values::{font_weight, font_style};
use servo_util::time::{ProfilerChan, profile};
use servo_util::time::{TimeProfilerChan, profile};
use servo_util::time;
pub type FontFamilyMap = HashMap<String, FontFamily>;
@ -25,18 +25,18 @@ trait FontListHandleMethods {
pub struct FontList {
family_map: FontFamilyMap,
handle: FontListHandle,
prof_chan: ProfilerChan,
time_profiler_chan: TimeProfilerChan,
}
impl FontList {
pub fn new(fctx: &FontContextHandle,
prof_chan: ProfilerChan)
time_profiler_chan: TimeProfilerChan)
-> FontList {
let handle = FontListHandle::new(fctx);
let mut list = FontList {
handle: handle,
family_map: HashMap::new(),
prof_chan: prof_chan.clone(),
time_profiler_chan: time_profiler_chan.clone(),
};
list.refresh(fctx);
list
@ -47,7 +47,7 @@ impl FontList {
// changed. Does OSX have a notification for this event?
//
// Should font families with entries be invalidated/refreshed too?
profile(time::GfxRegenAvailableFontsCategory, self.prof_chan.clone(), || {
profile(time::GfxRegenAvailableFontsCategory, self.time_profiler_chan.clone(), || {
self.family_map = self.handle.get_available_families();
});
}

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

@ -27,7 +27,7 @@ use servo_util::geometry;
use servo_util::opts::Opts;
use servo_util::smallvec::{SmallVec, SmallVec1};
use servo_util::task::send_on_failure;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time::{TimeProfilerChan, profile};
use servo_util::time;
use std::comm::{Receiver, Sender, channel};
use std::task::TaskBuilder;
@ -108,8 +108,8 @@ pub struct RenderTask<C> {
font_ctx: Box<FontContext>,
opts: Opts,
/// A channel to the profiler.
profiler_chan: ProfilerChan,
/// A channel to the time profiler.
time_profiler_chan: TimeProfilerChan,
/// The graphics context to use.
graphics_context: GraphicsContext,
@ -161,7 +161,7 @@ impl<C:RenderListener + Send> RenderTask<C> {
constellation_chan: ConstellationChan,
failure_msg: Failure,
opts: Opts,
profiler_chan: ProfilerChan,
time_profiler_chan: TimeProfilerChan,
shutdown_chan: Sender<()>) {
let mut builder = TaskBuilder::new().named("RenderTask");
let ConstellationChan(c) = constellation_chan.clone();
@ -182,10 +182,10 @@ impl<C:RenderListener + Send> RenderTask<C> {
font_ctx: box FontContext::new(FontContextInfo {
backend: opts.render_backend.clone(),
needs_font_list: false,
profiler_chan: profiler_chan.clone(),
time_profiler_chan: time_profiler_chan.clone(),
}),
opts: opts,
profiler_chan: profiler_chan,
time_profiler_chan: time_profiler_chan,
graphics_context: if cpu_painting {
CpuGraphicsContext
@ -280,7 +280,7 @@ impl<C:RenderListener + Send> RenderTask<C> {
/// FIXME(pcwalton): We will probably want to eventually send all layers belonging to a page in
/// one transaction, to avoid the user seeing inconsistent states.
fn render(&mut self, tiles: Vec<BufferRequest>, scale: f32, layer_id: LayerId) {
time::profile(time::RenderingCategory, self.profiler_chan.clone(), || {
time::profile(time::RenderingCategory, self.time_profiler_chan.clone(), || {
// FIXME: Try not to create a new array here.
let mut new_buffers = vec!();
@ -345,7 +345,7 @@ impl<C:RenderListener + Send> RenderTask<C> {
ctx.clear();
// Draw the display list.
profile(time::RenderingDrawingCategory, self.profiler_chan.clone(), || {
profile(time::RenderingDrawingCategory, self.time_profiler_chan.clone(), || {
display_list.draw_into_context(&mut ctx);
ctx.draw_target.flush();
});

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

@ -34,9 +34,10 @@ use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg, Navig
use servo_msg::constellation_msg::{PipelineId, ResizedWindowMsg, WindowSizeData};
use servo_msg::constellation_msg;
use servo_util::geometry::{DevicePixel, PagePx, ScreenPx, ViewportPx};
use servo_util::memory::MemoryProfilerChan;
use servo_util::opts::Opts;
use servo_util::time::{profile, ProfilerChan};
use servo_util::{time, url};
use servo_util::time::{profile, TimeProfilerChan};
use servo_util::{memory, time, url};
use std::io::timer::sleep;
use std::path::Path;
use std::rc::Rc;
@ -113,8 +114,11 @@ pub struct IOCompositor {
/// The channel on which messages can be sent to the constellation.
constellation_chan: ConstellationChan,
/// The channel on which messages can be sent to the profiler.
profiler_chan: ProfilerChan,
/// The channel on which messages can be sent to the time profiler.
time_profiler_chan: TimeProfilerChan,
/// The channel on which messages can be sent to the memory profiler.
memory_profiler_chan: MemoryProfilerChan,
/// Pending scroll to fragment event, if any
fragment_point: Option<Point2D<f32>>
@ -125,7 +129,8 @@ impl IOCompositor {
opts: Opts,
port: Receiver<Msg>,
constellation_chan: ConstellationChan,
profiler_chan: ProfilerChan) -> IOCompositor {
time_profiler_chan: TimeProfilerChan,
memory_profiler_chan: MemoryProfilerChan) -> IOCompositor {
let window: Rc<Window> = WindowMethods::new(app, opts.output_file.is_none());
// Create an initial layer tree.
@ -159,7 +164,8 @@ impl IOCompositor {
load_complete: false,
compositor_layer: None,
constellation_chan: constellation_chan,
profiler_chan: profiler_chan,
time_profiler_chan: time_profiler_chan,
memory_profiler_chan: memory_profiler_chan,
fragment_point: None
}
}
@ -168,12 +174,14 @@ impl IOCompositor {
opts: Opts,
port: Receiver<Msg>,
constellation_chan: ConstellationChan,
profiler_chan: ProfilerChan) {
time_profiler_chan: TimeProfilerChan,
memory_profiler_chan: MemoryProfilerChan) {
let mut compositor = IOCompositor::new(app,
opts,
port,
constellation_chan,
profiler_chan);
time_profiler_chan,
memory_profiler_chan);
compositor.update_zoom_transform();
// Starts the compositor, which listens for messages on the specified port.
@ -231,9 +239,12 @@ impl IOCompositor {
}
}
// Tell the profiler to shut down.
let ProfilerChan(ref chan) = self.profiler_chan;
chan.send(time::ExitMsg);
// Tell the profiler and memory profiler to shut down.
let TimeProfilerChan(ref time_profiler_chan) = self.time_profiler_chan;
time_profiler_chan.send(time::ExitMsg);
let MemoryProfilerChan(ref memory_profiler_chan) = self.memory_profiler_chan;
memory_profiler_chan.send(memory::ExitMsg);
}
fn handle_message(&mut self) {
@ -732,7 +743,7 @@ impl IOCompositor {
}
fn composite(&mut self) {
profile(time::CompositingCategory, self.profiler_chan.clone(), || {
profile(time::CompositingCategory, self.time_profiler_chan.clone(), || {
debug!("compositor: compositing");
// Adjust the layer dimensions as necessary to correspond to the size of the window.
self.scene.size = self.window_size.as_f32().to_untyped();

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

@ -16,8 +16,9 @@ use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphics
use servo_msg::compositor_msg::{Epoch, LayerBufferSet, LayerId, LayerMetadata, ReadyState};
use servo_msg::compositor_msg::{RenderListener, RenderState, ScriptListener, ScrollPolicy};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
use servo_util::memory::MemoryProfilerChan;
use servo_util::opts::Opts;
use servo_util::time::ProfilerChan;
use servo_util::time::TimeProfilerChan;
use std::comm::{channel, Sender, Receiver};
use url::Url;
@ -224,7 +225,8 @@ impl CompositorTask {
pub fn create(opts: Opts,
port: Receiver<Msg>,
constellation_chan: ConstellationChan,
profiler_chan: ProfilerChan) {
time_profiler_chan: TimeProfilerChan,
memory_profiler_chan: MemoryProfilerChan) {
let compositor = CompositorTask::new(opts.headless);
@ -234,12 +236,14 @@ impl CompositorTask {
opts,
port,
constellation_chan.clone(),
profiler_chan)
time_profiler_chan,
memory_profiler_chan)
}
Headless => {
headless::NullCompositor::create(port,
constellation_chan.clone(),
profiler_chan)
time_profiler_chan,
memory_profiler_chan)
}
};
}

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

@ -7,7 +7,9 @@ use compositing::*;
use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, ResizedWindowMsg, WindowSizeData};
use servo_util::time::ProfilerChan;
use servo_util::memory::MemoryProfilerChan;
use servo_util::memory;
use servo_util::time::TimeProfilerChan;
use servo_util::time;
/// Starts the compositor, which listens for messages on the specified port.
@ -28,7 +30,8 @@ impl NullCompositor {
pub fn create(port: Receiver<Msg>,
constellation_chan: ConstellationChan,
profiler_chan: ProfilerChan) {
time_profiler_chan: TimeProfilerChan,
memory_profiler_chan: MemoryProfilerChan) {
let compositor = NullCompositor::new(port);
// Tell the constellation about the initial fake size.
@ -51,7 +54,8 @@ impl NullCompositor {
}
}
profiler_chan.send(time::ExitMsg);
time_profiler_chan.send(time::ExitMsg);
memory_profiler_chan.send(memory::ExitMsg);
}
fn handle_message(&self, constellation_chan: ConstellationChan) {

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

@ -27,7 +27,7 @@ use servo_net::resource_task::ResourceTask;
use servo_net::resource_task;
use servo_util::geometry::PagePx;
use servo_util::opts::Opts;
use servo_util::time::ProfilerChan;
use servo_util::time::TimeProfilerChan;
use servo_util::url::parse_url;
use servo_util::task::spawn_named;
use std::cell::RefCell;
@ -48,7 +48,7 @@ pub struct Constellation {
next_pipeline_id: PipelineId,
pending_frames: Vec<FrameChange>,
pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>,
pub profiler_chan: ProfilerChan,
pub time_profiler_chan: TimeProfilerChan,
pub window_size: WindowSizeData,
pub opts: Opts,
}
@ -244,7 +244,7 @@ impl Constellation {
opts: &Opts,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
profiler_chan: ProfilerChan)
time_profiler_chan: TimeProfilerChan)
-> ConstellationChan {
let (constellation_port, constellation_chan) = ConstellationChan::new();
let constellation_chan_clone = constellation_chan.clone();
@ -261,7 +261,7 @@ impl Constellation {
next_pipeline_id: PipelineId(0),
pending_frames: vec!(),
pending_sizes: HashMap::new(),
profiler_chan: profiler_chan,
time_profiler_chan: time_profiler_chan,
window_size: WindowSizeData {
visible_viewport: TypedSize2D(800_f32, 600_f32),
initial_viewport: TypedSize2D(800_f32, 600_f32),
@ -424,7 +424,7 @@ impl Constellation {
self.compositor_chan.clone(),
self.image_cache_task.clone(),
self.resource_task.clone(),
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
self.window_size,
self.opts.clone(),
parse_url("about:failure", None));
@ -451,7 +451,7 @@ impl Constellation {
self.compositor_chan.clone(),
self.image_cache_task.clone(),
self.resource_task.clone(),
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
self.window_size,
self.opts.clone(),
url);
@ -576,7 +576,7 @@ impl Constellation {
self.chan.clone(),
self.compositor_chan.clone(),
self.image_cache_task.clone(),
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
self.opts.clone(),
source_pipeline.clone(),
url)
@ -589,7 +589,7 @@ impl Constellation {
self.compositor_chan.clone(),
self.image_cache_task.clone(),
self.resource_task.clone(),
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
self.window_size,
self.opts.clone(),
url)
@ -645,7 +645,7 @@ impl Constellation {
self.compositor_chan.clone(),
self.image_cache_task.clone(),
self.resource_task.clone(),
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
self.window_size,
self.opts.clone(),
url);

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

@ -49,7 +49,7 @@ use servo_util::geometry::Au;
use servo_util::geometry;
use servo_util::opts::Opts;
use servo_util::smallvec::{SmallVec, SmallVec1};
use servo_util::time::{ProfilerChan, profile};
use servo_util::time::{TimeProfilerChan, profile};
use servo_util::time;
use servo_util::task::send_on_failure;
use servo_util::workqueue::WorkQueue;
@ -98,8 +98,8 @@ pub struct LayoutTask {
/// The workers that we use for parallel operation.
pub parallel_traversal: Option<WorkQueue<*mut LayoutContext,UnsafeFlow>>,
/// The channel on which messages can be sent to the profiler.
pub profiler_chan: ProfilerChan,
/// The channel on which messages can be sent to the time profiler.
pub time_profiler_chan: TimeProfilerChan,
/// The command-line options.
pub opts: Opts,
@ -279,7 +279,7 @@ impl LayoutTask {
render_chan: RenderChan,
img_cache_task: ImageCacheTask,
opts: Opts,
profiler_chan: ProfilerChan,
time_profiler_chan: TimeProfilerChan,
shutdown_chan: Sender<()>) {
let mut builder = TaskBuilder::new().named("LayoutTask");
let ConstellationChan(con_chan) = constellation_chan.clone();
@ -294,7 +294,7 @@ impl LayoutTask {
render_chan,
img_cache_task,
&opts,
profiler_chan);
time_profiler_chan);
layout.start();
}
shutdown_chan.send(());
@ -310,7 +310,7 @@ impl LayoutTask {
render_chan: RenderChan,
image_cache_task: ImageCacheTask,
opts: &Opts,
profiler_chan: ProfilerChan)
time_profiler_chan: TimeProfilerChan)
-> LayoutTask {
let local_image_cache = Arc::new(Mutex::new(LocalImageCache(image_cache_task.clone())));
let screen_size = Size2D(Au(0), Au(0));
@ -334,7 +334,7 @@ impl LayoutTask {
display_list: None,
stylist: box new_stylist(),
parallel_traversal: parallel_traversal,
profiler_chan: profiler_chan,
time_profiler_chan: time_profiler_chan,
opts: opts.clone(),
dirty: Rect::zero(),
}
@ -352,7 +352,7 @@ impl LayoutTask {
let font_context_info = FontContextInfo {
backend: self.opts.render_backend,
needs_font_list: true,
profiler_chan: self.profiler_chan.clone(),
time_profiler_chan: self.time_profiler_chan.clone(),
};
LayoutContext {
@ -374,13 +374,13 @@ impl LayoutTask {
match self.port.recv() {
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
ReflowMsg(data) => {
profile(time::LayoutPerformCategory, self.profiler_chan.clone(), || {
profile(time::LayoutPerformCategory, self.time_profiler_chan.clone(), || {
self.handle_reflow(data);
});
}
QueryMsg(query) => {
let mut query = Some(query);
profile(time::LayoutQueryCategory, self.profiler_chan.clone(), || {
profile(time::LayoutQueryCategory, self.time_profiler_chan.clone(), || {
self.handle_query(query.take_unwrap());
});
}
@ -529,7 +529,7 @@ impl LayoutTask {
// NOTE: this currently computes borders, so any pruning should separate that
// operation out.
parallel::traverse_flow_tree_preorder(layout_root,
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
layout_context,
traversal);
}
@ -600,7 +600,7 @@ impl LayoutTask {
};
let mut layout_root = profile(time::LayoutStyleRecalcCategory,
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
|| {
// Perform CSS selector matching and flow construction.
match self.parallel_traversal {
@ -630,7 +630,7 @@ impl LayoutTask {
self.verify_flow_tree(&mut layout_root);
// Propagate damage.
profile(time::LayoutDamagePropagateCategory, self.profiler_chan.clone(), || {
profile(time::LayoutDamagePropagateCategory, self.time_profiler_chan.clone(), || {
layout_root.get_mut().traverse_preorder(&mut PropagateDamageTraversal {
all_style_damage: all_style_damage
});
@ -639,7 +639,7 @@ impl LayoutTask {
// Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes.
profile(time::LayoutMainCategory, self.profiler_chan.clone(), || {
profile(time::LayoutMainCategory, self.time_profiler_chan.clone(), || {
match self.parallel_traversal {
None => {
// Sequential mode.
@ -654,7 +654,7 @@ impl LayoutTask {
// Build the display list if necessary, and send it to the renderer.
if data.goal == ReflowForDisplay {
profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone(), || {
profile(time::LayoutDispListBuildCategory, self.time_profiler_chan.clone(), || {
layout_ctx.dirty = flow::base(layout_root.get()).position.clone();
match self.parallel_traversal {
@ -666,7 +666,7 @@ impl LayoutTask {
}
Some(ref mut traversal) => {
parallel::build_display_list_for_subtree(&mut layout_root,
self.profiler_chan.clone(),
self.time_profiler_chan.clone(),
&mut layout_ctx,
traversal);
}

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

@ -20,7 +20,7 @@ use layout::wrapper::{layout_node_to_unsafe_layout_node, layout_node_from_unsafe
use layout::wrapper::{ThreadSafeLayoutNode, UnsafeLayoutNode};
use gfx::display_list::OpaqueNode;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time::{TimeProfilerChan, profile};
use servo_util::time;
use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
use std::mem;
@ -526,14 +526,14 @@ pub fn recalc_style_for_subtree(root_node: &LayoutNode,
}
pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
profiler_chan: ProfilerChan,
time_profiler_chan: TimeProfilerChan,
layout_context: &mut LayoutContext,
queue: &mut WorkQueue<*mut LayoutContext,UnsafeFlow>) {
unsafe {
queue.data = mem::transmute(layout_context)
}
profile(time::LayoutParallelWarmupCategory, profiler_chan, || {
profile(time::LayoutParallelWarmupCategory, time_profiler_chan, || {
queue.push(WorkUnit {
fun: assign_widths,
data: mut_owned_flow_to_unsafe_flow(root),
@ -546,14 +546,14 @@ pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
}
pub fn build_display_list_for_subtree(root: &mut FlowRef,
profiler_chan: ProfilerChan,
time_profiler_chan: TimeProfilerChan,
layout_context: &mut LayoutContext,
queue: &mut WorkQueue<*mut LayoutContext,UnsafeFlow>) {
unsafe {
queue.data = mem::transmute(layout_context)
}
profile(time::LayoutParallelWarmupCategory, profiler_chan, || {
profile(time::LayoutParallelWarmupCategory, time_profiler_chan, || {
queue.push(WorkUnit {
fun: compute_absolute_position,
data: mut_owned_flow_to_unsafe_flow(root),

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

@ -16,7 +16,7 @@ use servo_msg::constellation_msg::WindowSizeData;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::opts::Opts;
use servo_util::time::ProfilerChan;
use servo_util::time::TimeProfilerChan;
use std::rc::Rc;
use url::Url;
@ -49,7 +49,7 @@ impl Pipeline {
constellation_chan: ConstellationChan,
compositor_chan: CompositorChan,
image_cache_task: ImageCacheTask,
profiler_chan: ProfilerChan,
time_profiler_chan: TimeProfilerChan,
opts: Opts,
script_pipeline: Rc<Pipeline>,
url: Url)
@ -70,7 +70,7 @@ impl Pipeline {
constellation_chan.clone(),
failure.clone(),
opts.clone(),
profiler_chan.clone(),
time_profiler_chan.clone(),
render_shutdown_chan);
LayoutTask::create(id,
@ -82,7 +82,7 @@ impl Pipeline {
render_chan.clone(),
image_cache_task.clone(),
opts.clone(),
profiler_chan,
time_profiler_chan,
layout_shutdown_chan);
let new_layout_info = NewLayoutInfo {
@ -111,7 +111,7 @@ impl Pipeline {
compositor_chan: CompositorChan,
image_cache_task: ImageCacheTask,
resource_task: ResourceTask,
profiler_chan: ProfilerChan,
time_profiler_chan: TimeProfilerChan,
window_size: WindowSizeData,
opts: Opts,
url: Url)
@ -152,7 +152,7 @@ impl Pipeline {
constellation_chan.clone(),
failure.clone(),
opts.clone(),
profiler_chan.clone(),
time_profiler_chan.clone(),
render_shutdown_chan);
LayoutTask::create(id,
@ -164,7 +164,7 @@ impl Pipeline {
render_chan.clone(),
image_cache_task,
opts.clone(),
profiler_chan,
time_profiler_chan,
layout_shutdown_chan);
pipeline

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

@ -63,7 +63,9 @@ use servo_net::image_cache_task::{ImageCacheTask, SyncImageCacheTask};
#[cfg(not(test))]
use servo_net::resource_task::ResourceTask;
#[cfg(not(test))]
use servo_util::time::Profiler;
use servo_util::time::TimeProfiler;
#[cfg(not(test))]
use servo_util::memory::MemoryProfiler;
#[cfg(not(test))]
use servo_util::opts;
@ -168,10 +170,11 @@ pub fn run(opts: opts::Opts) {
let mut pool = green::SchedPool::new(pool_config);
let (compositor_port, compositor_chan) = CompositorChan::new();
let profiler_chan = Profiler::create(opts.profiler_period);
let time_profiler_chan = TimeProfiler::create(opts.time_profiler_period);
let memory_profiler_chan = MemoryProfiler::create(opts.memory_profiler_period);
let opts_clone = opts.clone();
let profiler_chan_clone = profiler_chan.clone();
let time_profiler_chan_clone = time_profiler_chan.clone();
let (result_chan, result_port) = channel();
pool.spawn(TaskOpts::new(), proc() {
@ -190,7 +193,7 @@ pub fn run(opts: opts::Opts) {
opts,
resource_task,
image_cache_task,
profiler_chan_clone);
time_profiler_chan_clone);
// Send the URL command to the constellation.
for filename in opts.urls.iter() {
@ -217,7 +220,8 @@ pub fn run(opts: opts::Opts) {
CompositorTask::create(opts,
compositor_port,
constellation_chan,
profiler_chan);
time_profiler_chan,
memory_profiler_chan);
pool.shutdown();
}

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

@ -0,0 +1,158 @@
/* 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/. */
//! Memory profiling functions.
use std::io::timer::sleep;
#[cfg(target_os="linux")]
use std::io::File;
#[cfg(target_os="linux")]
use std::os::page_size;
use task::spawn_named;
pub struct MemoryProfilerChan(pub Sender<MemoryProfilerMsg>);
impl MemoryProfilerChan {
pub fn send(&self, msg: MemoryProfilerMsg) {
let MemoryProfilerChan(ref c) = *self;
c.send(msg);
}
}
pub enum MemoryProfilerMsg {
/// Message used to force print the memory profiling metrics.
PrintMsg,
/// Tells the memory profiler to shut down.
ExitMsg,
}
pub struct MemoryProfiler {
pub port: Receiver<MemoryProfilerMsg>,
}
impl MemoryProfiler {
pub fn create(period: Option<f64>) -> MemoryProfilerChan {
let (chan, port) = channel();
match period {
Some(period) => {
let period = (period * 1000f64) as u64;
let chan = chan.clone();
spawn_named("Memory profiler timer", proc() {
loop {
sleep(period);
if chan.send_opt(PrintMsg).is_err() {
break;
}
}
});
// Spawn the memory profiler.
spawn_named("Memory profiler", proc() {
let memory_profiler = MemoryProfiler::new(port);
memory_profiler.start();
});
}
None => {
// No-op to handle messages when the memory profiler is
// inactive.
spawn_named("Memory profiler", proc() {
loop {
match port.recv_opt() {
Err(_) | Ok(ExitMsg) => break,
_ => {}
}
}
});
}
}
MemoryProfilerChan(chan)
}
pub fn new(port: Receiver<MemoryProfilerMsg>) -> MemoryProfiler {
MemoryProfiler {
port: port
}
}
pub fn start(&self) {
loop {
match self.port.recv_opt() {
Ok(msg) => {
if !self.handle_msg(msg) {
break
}
}
_ => break
}
}
}
fn handle_msg(&self, msg: MemoryProfilerMsg) -> bool {
match msg {
PrintMsg => {
self.handle_print_msg();
true
},
ExitMsg => false
}
}
fn print_measurement(path: &str, nbytes: Option<i64>) {
match nbytes {
Some(nbytes) => {
let mebi = 1024f64 * 1024f64;
println!("{:12s}: {:12.2f}", path, (nbytes as f64) / mebi);
}
None => {
println!("{:12s}: {:>12s}", path, "???");
}
}
}
fn handle_print_msg(&self) {
println!("{:12s}: {:12s}", "_category_", "_size (MiB)_");
MemoryProfiler::print_measurement("vsize", get_vsize());
MemoryProfiler::print_measurement("resident", get_resident());
println!("");
}
}
// Like std::macros::try!, but for Option<>.
macro_rules! option_try(
($e:expr) => (match $e { Some(e) => e, None => return None })
)
#[cfg(target_os="linux")]
fn get_proc_self_statm_field(field: uint) -> Option<i64> {
let mut f = File::open(&Path::new("/proc/self/statm"));
match f.read_to_str() {
Ok(contents) => {
let s = option_try!(contents.as_slice().words().nth(field));
let npages: i64 = option_try!(from_str(s));
Some(npages * (page_size() as i64))
}
Err(_) => None
}
}
#[cfg(target_os="linux")]
fn get_vsize() -> Option<i64> {
get_proc_self_statm_field(0)
}
#[cfg(not(target_os="linux"))]
fn get_vsize() -> Option<i64> {
None
}
#[cfg(target_os="linux")]
fn get_resident() -> Option<i64> {
get_proc_self_statm_field(1)
}
#[cfg(not(target_os="linux"))]
fn get_resident() -> Option<i64> {
None
}

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

@ -41,9 +41,13 @@ pub struct Opts {
/// platform default setting.
pub device_pixels_per_px: Option<ScaleFactor<ScreenPx, DevicePixel, f32>>,
/// `None` to disable the profiler or `Some` with an interval in seconds to enable it and cause
/// it to produce output on that interval (`-p`).
pub profiler_period: Option<f64>,
/// `None` to disable the time profiler or `Some` with an interval in seconds to enable it and
/// cause it to produce output on that interval (`-p`).
pub time_profiler_period: Option<f64>,
/// `None` to disable the memory profiler or `Some` with an interval in seconds to enable it
/// and cause it to produce output on that interval (`-m`).
pub memory_profiler_period: Option<f64>,
/// The number of threads to use for layout (`-y`). Defaults to 1, which results in a recursive
/// sequential algorithm.
@ -85,6 +89,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
getopts::optopt("", "device-pixel-ratio", "Device pixels per px", ""),
getopts::optopt("t", "threads", "Number of render threads", "1"),
getopts::optflagopt("p", "profile", "Profiler flag and output interval", "10"),
getopts::optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10"),
getopts::optflag("x", "exit", "Exit after load flag"),
getopts::optopt("y", "layout-threads", "Number of threads to use for layout", "1"),
getopts::optflag("z", "headless", "Headless mode"),
@ -147,8 +152,11 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
None => 1, // FIXME: Number of cores.
};
// if only flag is present, default to 5 second period
let profiler_period = opt_match.opt_default("p", "5").map(|period| {
// If only the flag is present, default to a 5 second period for both profilers.
let time_profiler_period = opt_match.opt_default("p", "5").map(|period| {
from_str(period.as_slice()).unwrap()
});
let memory_profiler_period = opt_match.opt_default("m", "5").map(|period| {
from_str(period.as_slice()).unwrap()
});
@ -166,7 +174,8 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
cpu_painting: cpu_painting,
tile_size: tile_size,
device_pixels_per_px: device_pixels_per_px,
profiler_period: profiler_period,
time_profiler_period: time_profiler_period,
memory_profiler_period: memory_profiler_period,
layout_threads: layout_threads,
exit_after_load: opt_match.opt_present("x"),
output_file: opt_match.opt_str("o"),

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

@ -14,18 +14,18 @@ use task::{spawn_named};
// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan(pub Sender<ProfilerMsg>);
pub struct TimeProfilerChan(pub Sender<TimeProfilerMsg>);
impl ProfilerChan {
pub fn send(&self, msg: ProfilerMsg) {
let ProfilerChan(ref c) = *self;
impl TimeProfilerChan {
pub fn send(&self, msg: TimeProfilerMsg) {
let TimeProfilerChan(ref c) = *self;
c.send(msg);
}
}
pub enum ProfilerMsg {
pub enum TimeProfilerMsg {
/// Normal message used for reporting time
TimeMsg(ProfilerCategory, f64),
TimeMsg(TimeProfilerCategory, f64),
/// Message used to force print the profiling metrics
PrintMsg,
/// Tells the profiler to shut down.
@ -34,7 +34,7 @@ pub enum ProfilerMsg {
#[repr(u32)]
#[deriving(Eq, Clone, Ord, TotalEq, TotalOrd)]
pub enum ProfilerCategory {
pub enum TimeProfilerCategory {
CompositingCategory,
LayoutQueryCategory,
LayoutPerformCategory,
@ -54,14 +54,14 @@ pub enum ProfilerCategory {
NumBuckets,
}
impl ProfilerCategory {
impl TimeProfilerCategory {
// convenience function to not have to cast every time
pub fn num_buckets() -> uint {
NumBuckets as uint
}
// enumeration of all ProfilerCategory types
fn empty_buckets() -> ProfilerBuckets {
// enumeration of all TimeProfilerCategory types
fn empty_buckets() -> TimeProfilerBuckets {
let mut buckets = TreeMap::new();
buckets.insert(CompositingCategory, vec!());
buckets.insert(LayoutQueryCategory, vec!());
@ -100,23 +100,23 @@ impl ProfilerCategory {
}
}
type ProfilerBuckets = TreeMap<ProfilerCategory, Vec<f64>>;
type TimeProfilerBuckets = TreeMap<TimeProfilerCategory, Vec<f64>>;
// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
pub port: Receiver<ProfilerMsg>,
buckets: ProfilerBuckets,
pub last_msg: Option<ProfilerMsg>,
pub struct TimeProfiler {
pub port: Receiver<TimeProfilerMsg>,
buckets: TimeProfilerBuckets,
pub last_msg: Option<TimeProfilerMsg>,
}
impl Profiler {
pub fn create(period: Option<f64>) -> ProfilerChan {
impl TimeProfiler {
pub fn create(period: Option<f64>) -> TimeProfilerChan {
let (chan, port) = channel();
match period {
Some(period) => {
let period = (period * 1000f64) as u64;
let chan = chan.clone();
spawn_named("Profiler timer", proc() {
spawn_named("Time profiler timer", proc() {
loop {
sleep(period);
if chan.send_opt(PrintMsg).is_err() {
@ -124,15 +124,15 @@ impl Profiler {
}
}
});
// Spawn the profiler
spawn_named("Profiler", proc() {
let mut profiler = Profiler::new(port);
// Spawn the time profiler.
spawn_named("Time profiler", proc() {
let mut profiler = TimeProfiler::new(port);
profiler.start();
});
}
None => {
// no-op to handle profiler messages when the profiler is inactive
spawn_named("Profiler", proc() {
// No-op to handle messages when the time profiler is inactive.
spawn_named("Time profiler", proc() {
loop {
match port.recv_opt() {
Err(_) | Ok(ExitMsg) => break,
@ -143,13 +143,13 @@ impl Profiler {
}
}
ProfilerChan(chan)
TimeProfilerChan(chan)
}
pub fn new(port: Receiver<ProfilerMsg>) -> Profiler {
Profiler {
pub fn new(port: Receiver<TimeProfilerMsg>) -> TimeProfiler {
TimeProfiler {
port: port,
buckets: ProfilerCategory::empty_buckets(),
buckets: TimeProfilerCategory::empty_buckets(),
last_msg: None,
}
}
@ -168,7 +168,7 @@ impl Profiler {
}
}
fn handle_msg(&mut self, msg: ProfilerMsg) -> bool {
fn handle_msg(&mut self, msg: TimeProfilerMsg) -> bool {
match msg {
TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
PrintMsg => match self.last_msg {
@ -210,15 +210,15 @@ impl Profiler {
}
pub fn profile<T>(category: ProfilerCategory,
profiler_chan: ProfilerChan,
pub fn profile<T>(category: TimeProfilerCategory,
time_profiler_chan: TimeProfilerChan,
callback: || -> T)
-> T {
let start_time = precise_time_ns();
let val = callback();
let end_time = precise_time_ns();
let ms = (end_time - start_time) as f64 / 1000000f64;
profiler_chan.send(TimeMsg(category, ms));
time_profiler_chan.send(TimeMsg(category, ms));
return val;
}
@ -236,6 +236,6 @@ pub fn time<T>(msg: &str, callback: || -> T) -> T{
// ensure that the order of the buckets matches the order of the enum categories
#[test]
fn check_order() {
let buckets = ProfilerCategory::empty_buckets();
let buckets = TimeProfilerCategory::empty_buckets();
assert!(buckets.len() == NumBuckets as uint);
}

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

@ -29,6 +29,7 @@ extern crate std_url = "url";
pub mod cache;
pub mod debug_utils;
pub mod geometry;
pub mod memory;
pub mod namespace;
pub mod opts;
pub mod range;