mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
compositing: Add memory reporter for WebRender. (#36557)
This adds a memory reporter for WebRender's memory usage. I seeded it with a couple entries that looked reasonable based on https://searchfox.org/mozilla-central/rev/2c71f1e9b5947612abdc16b64008162c58c1b9d3/gfx/thebes/gfxPlatform.cpp#722-738. Testing: Verified that new numbers appear in about:memory for servo.org. The new images category is surprisingly large (40mb). Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
afe98e9e1e
commit
af000d6c91
9 changed files with 98 additions and 8 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1106,6 +1106,7 @@ dependencies = [
|
||||||
"pixels",
|
"pixels",
|
||||||
"profile_traits",
|
"profile_traits",
|
||||||
"script_traits",
|
"script_traits",
|
||||||
|
"servo_allocator",
|
||||||
"servo_config",
|
"servo_config",
|
||||||
"servo_geometry",
|
"servo_geometry",
|
||||||
"stylo_traits",
|
"stylo_traits",
|
||||||
|
@ -1114,6 +1115,7 @@ dependencies = [
|
||||||
"webrender",
|
"webrender",
|
||||||
"webrender_api",
|
"webrender_api",
|
||||||
"webxr",
|
"webxr",
|
||||||
|
"wr_malloc_size_of",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1132,6 +1134,7 @@ dependencies = [
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
"log",
|
"log",
|
||||||
"pixels",
|
"pixels",
|
||||||
|
"profile_traits",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"serde",
|
"serde",
|
||||||
"servo_geometry",
|
"servo_geometry",
|
||||||
|
@ -4353,6 +4356,7 @@ dependencies = [
|
||||||
"servo-media",
|
"servo-media",
|
||||||
"servo-media-dummy",
|
"servo-media-dummy",
|
||||||
"servo-media-gstreamer",
|
"servo-media-gstreamer",
|
||||||
|
"servo_allocator",
|
||||||
"servo_config",
|
"servo_config",
|
||||||
"servo_geometry",
|
"servo_geometry",
|
||||||
"servo_url",
|
"servo_url",
|
||||||
|
|
|
@ -35,6 +35,7 @@ net = { path = "../net" }
|
||||||
pixels = { path = "../pixels" }
|
pixels = { path = "../pixels" }
|
||||||
profile_traits = { workspace = true }
|
profile_traits = { workspace = true }
|
||||||
script_traits = { workspace = true }
|
script_traits = { workspace = true }
|
||||||
|
servo_allocator = { path = "../allocator" }
|
||||||
servo_config = { path = "../config" }
|
servo_config = { path = "../config" }
|
||||||
servo_geometry = { path = "../geometry" }
|
servo_geometry = { path = "../geometry" }
|
||||||
stylo_traits = { workspace = true }
|
stylo_traits = { workspace = true }
|
||||||
|
@ -42,6 +43,7 @@ tracing = { workspace = true, optional = true }
|
||||||
webrender = { workspace = true }
|
webrender = { workspace = true }
|
||||||
webrender_api = { workspace = true }
|
webrender_api = { workspace = true }
|
||||||
webxr = { path = "../webxr", optional = true }
|
webxr = { path = "../webxr", optional = true }
|
||||||
|
wr_malloc_size_of = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
surfman = { workspace = true }
|
surfman = { workspace = true }
|
||||||
|
|
|
@ -34,8 +34,9 @@ use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
use pixels::{CorsStatus, Image, ImageFrame, PixelFormat};
|
use pixels::{CorsStatus, Image, ImageFrame, PixelFormat};
|
||||||
|
use profile_traits::mem::{ProcessReports, ProfilerRegistration, Report, ReportKind};
|
||||||
use profile_traits::time::{self as profile_time, ProfilerCategory};
|
use profile_traits::time::{self as profile_time, ProfilerCategory};
|
||||||
use profile_traits::time_profile;
|
use profile_traits::{path, time_profile};
|
||||||
use servo_config::opts;
|
use servo_config::opts;
|
||||||
use servo_geometry::DeviceIndependentPixel;
|
use servo_geometry::DeviceIndependentPixel;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
|
@ -147,6 +148,10 @@ pub struct IOCompositor {
|
||||||
/// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and
|
/// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and
|
||||||
/// ScriptThread with a deluge of animation ticks.
|
/// ScriptThread with a deluge of animation ticks.
|
||||||
last_animation_tick: Instant,
|
last_animation_tick: Instant,
|
||||||
|
|
||||||
|
/// A handle to the memory profiler which will automatically unregister
|
||||||
|
/// when it's dropped.
|
||||||
|
_mem_profiler_registration: ProfilerRegistration,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Why we need to be repainted. This is used for debugging.
|
/// Why we need to be repainted. This is used for debugging.
|
||||||
|
@ -391,6 +396,11 @@ impl ServoRenderer {
|
||||||
|
|
||||||
impl IOCompositor {
|
impl IOCompositor {
|
||||||
pub fn new(state: InitialCompositorState, convert_mouse_to_touch: bool) -> Self {
|
pub fn new(state: InitialCompositorState, convert_mouse_to_touch: bool) -> Self {
|
||||||
|
let registration = state.mem_profiler_chan.prepare_memory_reporting(
|
||||||
|
"compositor".into(),
|
||||||
|
state.sender.clone(),
|
||||||
|
CompositorMsg::CollectMemoryReport,
|
||||||
|
);
|
||||||
let compositor = IOCompositor {
|
let compositor = IOCompositor {
|
||||||
global: Rc::new(RefCell::new(ServoRenderer {
|
global: Rc::new(RefCell::new(ServoRenderer {
|
||||||
shutdown_state: state.shutdown_state,
|
shutdown_state: state.shutdown_state,
|
||||||
|
@ -414,6 +424,7 @@ impl IOCompositor {
|
||||||
rendering_context: state.rendering_context,
|
rendering_context: state.rendering_context,
|
||||||
pending_frames: 0,
|
pending_frames: 0,
|
||||||
last_animation_tick: Instant::now(),
|
last_animation_tick: Instant::now(),
|
||||||
|
_mem_profiler_registration: registration,
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -496,6 +507,30 @@ impl IOCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
|
CompositorMsg::CollectMemoryReport(sender) => {
|
||||||
|
let ops =
|
||||||
|
wr_malloc_size_of::MallocSizeOfOps::new(servo_allocator::usable_size, None);
|
||||||
|
let report = self.global.borrow().webrender_api.report_memory(ops);
|
||||||
|
let reports = vec![
|
||||||
|
Report {
|
||||||
|
path: path!["webrender", "fonts"],
|
||||||
|
kind: ReportKind::ExplicitJemallocHeapSize,
|
||||||
|
size: report.fonts,
|
||||||
|
},
|
||||||
|
Report {
|
||||||
|
path: path!["webrender", "images"],
|
||||||
|
kind: ReportKind::ExplicitJemallocHeapSize,
|
||||||
|
size: report.images,
|
||||||
|
},
|
||||||
|
Report {
|
||||||
|
path: path!["webrender", "display-list"],
|
||||||
|
kind: ReportKind::ExplicitJemallocHeapSize,
|
||||||
|
size: report.display_list,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
sender.send(ProcessReports::new(reports));
|
||||||
|
},
|
||||||
|
|
||||||
CompositorMsg::ChangeRunningAnimationsState(
|
CompositorMsg::ChangeRunningAnimationsState(
|
||||||
webview_id,
|
webview_id,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
|
|
|
@ -57,6 +57,7 @@ mod from_constellation {
|
||||||
Self::GetClientWindowRect(..) => target!("GetClientWindowRect"),
|
Self::GetClientWindowRect(..) => target!("GetClientWindowRect"),
|
||||||
Self::GetScreenSize(..) => target!("GetScreenSize"),
|
Self::GetScreenSize(..) => target!("GetScreenSize"),
|
||||||
Self::GetAvailableScreenSize(..) => target!("GetAvailableScreenSize"),
|
Self::GetAvailableScreenSize(..) => target!("GetAvailableScreenSize"),
|
||||||
|
Self::CollectMemoryReport(..) => target!("CollectMemoryReport"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ serde = { workspace = true }
|
||||||
servo-media = { workspace = true }
|
servo-media = { workspace = true }
|
||||||
servo-media-dummy = { workspace = true }
|
servo-media-dummy = { workspace = true }
|
||||||
servo-media-gstreamer = { workspace = true, optional = true }
|
servo-media-gstreamer = { workspace = true, optional = true }
|
||||||
|
servo_allocator = { path = "../allocator" }
|
||||||
servo_config = { path = "../config" }
|
servo_config = { path = "../config" }
|
||||||
servo_geometry = { path = "../geometry" }
|
servo_geometry = { path = "../geometry" }
|
||||||
servo_url = { path = "../url" }
|
servo_url = { path = "../url" }
|
||||||
|
|
|
@ -373,6 +373,7 @@ impl Servo {
|
||||||
clear_color,
|
clear_color,
|
||||||
upload_method,
|
upload_method,
|
||||||
workers,
|
workers,
|
||||||
|
size_of_op: Some(servo_allocator::usable_size),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -27,6 +27,7 @@ image = { workspace = true }
|
||||||
ipc-channel = { workspace = true }
|
ipc-channel = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
pixels = { path = '../../pixels' }
|
pixels = { path = '../../pixels' }
|
||||||
|
profile_traits = { path = '../profile' }
|
||||||
raw-window-handle = { version = "0.6" }
|
raw-window-handle = { version = "0.6" }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
servo_geometry = { path = "../../geometry" }
|
servo_geometry = { path = "../../geometry" }
|
||||||
|
|
|
@ -29,6 +29,7 @@ use display_list::CompositorDisplayListInfo;
|
||||||
use embedder_traits::{CompositorHitTestResult, ScreenGeometry};
|
use embedder_traits::{CompositorHitTestResult, ScreenGeometry};
|
||||||
use euclid::default::Size2D as UntypedSize2D;
|
use euclid::default::Size2D as UntypedSize2D;
|
||||||
use ipc_channel::ipc::{self, IpcSharedMemory};
|
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||||
|
use profile_traits::mem::{OpaqueSender, ReportsChan};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
|
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
|
||||||
use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect};
|
use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect};
|
||||||
|
@ -50,6 +51,12 @@ pub struct CompositorProxy {
|
||||||
pub event_loop_waker: Box<dyn EventLoopWaker>,
|
pub event_loop_waker: Box<dyn EventLoopWaker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OpaqueSender<CompositorMsg> for CompositorProxy {
|
||||||
|
fn send(&self, message: CompositorMsg) {
|
||||||
|
CompositorProxy::send(self, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CompositorProxy {
|
impl CompositorProxy {
|
||||||
pub fn send(&self, msg: CompositorMsg) {
|
pub fn send(&self, msg: CompositorMsg) {
|
||||||
if let Err(err) = self.sender.send(msg) {
|
if let Err(err) = self.sender.send(msg) {
|
||||||
|
@ -154,6 +161,10 @@ pub enum CompositorMsg {
|
||||||
/// Get the available screen size (without toolbars and docks) for the screen
|
/// Get the available screen size (without toolbars and docks) for the screen
|
||||||
/// the client window inhabits.
|
/// the client window inhabits.
|
||||||
GetAvailableScreenSize(WebViewId, IpcSender<DeviceIndependentIntSize>),
|
GetAvailableScreenSize(WebViewId, IpcSender<DeviceIndependentIntSize>),
|
||||||
|
|
||||||
|
/// Measure the current memory usage associated with the compositor.
|
||||||
|
/// The report must be sent on the provided channel once it's complete.
|
||||||
|
CollectMemoryReport(ReportsChan),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for CompositorMsg {
|
impl Debug for CompositorMsg {
|
||||||
|
|
|
@ -50,6 +50,21 @@ where
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct ProfilerChan(pub IpcSender<ProfilerMsg>);
|
pub struct ProfilerChan(pub IpcSender<ProfilerMsg>);
|
||||||
|
|
||||||
|
/// A handle that encompasses a registration with the memory profiler.
|
||||||
|
/// The registration is tied to the lifetime of this type; the memory
|
||||||
|
/// profiler unregister the reporter when this object is dropped.
|
||||||
|
pub struct ProfilerRegistration {
|
||||||
|
sender: ProfilerChan,
|
||||||
|
reporter_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ProfilerRegistration {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.sender
|
||||||
|
.send(ProfilerMsg::UnregisterReporter(self.reporter_name.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ProfilerChan {
|
impl ProfilerChan {
|
||||||
/// Send `msg` on this `IpcSender`.
|
/// Send `msg` on this `IpcSender`.
|
||||||
///
|
///
|
||||||
|
@ -60,15 +75,15 @@ impl ProfilerChan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs `f()` with memory profiling.
|
/// Register a new reporter and return a handle to automatically
|
||||||
pub fn run_with_memory_reporting<F, M, T, C>(
|
/// unregister it in the future.
|
||||||
|
pub fn prepare_memory_reporting<M, T, C>(
|
||||||
&self,
|
&self,
|
||||||
f: F,
|
|
||||||
reporter_name: String,
|
reporter_name: String,
|
||||||
channel_for_reporter: C,
|
channel_for_reporter: C,
|
||||||
msg: M,
|
msg: M,
|
||||||
) where
|
) -> ProfilerRegistration
|
||||||
F: FnOnce(),
|
where
|
||||||
M: Fn(ReportsChan) -> T + Send + 'static,
|
M: Fn(ReportsChan) -> T + Send + 'static,
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
C: OpaqueSender<T> + Send + 'static,
|
C: OpaqueSender<T> + Send + 'static,
|
||||||
|
@ -88,9 +103,28 @@ impl ProfilerChan {
|
||||||
Reporter(reporter_sender),
|
Reporter(reporter_sender),
|
||||||
));
|
));
|
||||||
|
|
||||||
f();
|
ProfilerRegistration {
|
||||||
|
sender: self.clone(),
|
||||||
|
reporter_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.send(ProfilerMsg::UnregisterReporter(reporter_name));
|
/// Runs `f()` with memory profiling.
|
||||||
|
pub fn run_with_memory_reporting<F, M, T, C>(
|
||||||
|
&self,
|
||||||
|
f: F,
|
||||||
|
reporter_name: String,
|
||||||
|
channel_for_reporter: C,
|
||||||
|
msg: M,
|
||||||
|
) where
|
||||||
|
F: FnOnce(),
|
||||||
|
M: Fn(ReportsChan) -> T + Send + 'static,
|
||||||
|
T: Send + 'static,
|
||||||
|
C: OpaqueSender<T> + Send + 'static,
|
||||||
|
{
|
||||||
|
let _registration = self.prepare_memory_reporting(reporter_name, channel_for_reporter, msg);
|
||||||
|
|
||||||
|
f();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue