зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
f9030541e2
Коммит
7eeecb11b3
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче