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",
|
||||
"profile_traits",
|
||||
"script_traits",
|
||||
"servo_allocator",
|
||||
"servo_config",
|
||||
"servo_geometry",
|
||||
"stylo_traits",
|
||||
|
@ -1114,6 +1115,7 @@ dependencies = [
|
|||
"webrender",
|
||||
"webrender_api",
|
||||
"webxr",
|
||||
"wr_malloc_size_of",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1132,6 +1134,7 @@ dependencies = [
|
|||
"ipc-channel",
|
||||
"log",
|
||||
"pixels",
|
||||
"profile_traits",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"servo_geometry",
|
||||
|
@ -4353,6 +4356,7 @@ dependencies = [
|
|||
"servo-media",
|
||||
"servo-media-dummy",
|
||||
"servo-media-gstreamer",
|
||||
"servo_allocator",
|
||||
"servo_config",
|
||||
"servo_geometry",
|
||||
"servo_url",
|
||||
|
|
|
@ -35,6 +35,7 @@ net = { path = "../net" }
|
|||
pixels = { path = "../pixels" }
|
||||
profile_traits = { workspace = true }
|
||||
script_traits = { workspace = true }
|
||||
servo_allocator = { path = "../allocator" }
|
||||
servo_config = { path = "../config" }
|
||||
servo_geometry = { path = "../geometry" }
|
||||
stylo_traits = { workspace = true }
|
||||
|
@ -42,6 +43,7 @@ tracing = { workspace = true, optional = true }
|
|||
webrender = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
webxr = { path = "../webxr", optional = true }
|
||||
wr_malloc_size_of = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
surfman = { workspace = true }
|
||||
|
|
|
@ -34,8 +34,9 @@ use ipc_channel::ipc::{self, IpcSharedMemory};
|
|||
use libc::c_void;
|
||||
use log::{debug, info, trace, warn};
|
||||
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_profile;
|
||||
use profile_traits::{path, time_profile};
|
||||
use servo_config::opts;
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
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
|
||||
/// ScriptThread with a deluge of animation ticks.
|
||||
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.
|
||||
|
@ -391,6 +396,11 @@ impl ServoRenderer {
|
|||
|
||||
impl IOCompositor {
|
||||
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 {
|
||||
global: Rc::new(RefCell::new(ServoRenderer {
|
||||
shutdown_state: state.shutdown_state,
|
||||
|
@ -414,6 +424,7 @@ impl IOCompositor {
|
|||
rendering_context: state.rendering_context,
|
||||
pending_frames: 0,
|
||||
last_animation_tick: Instant::now(),
|
||||
_mem_profiler_registration: registration,
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -496,6 +507,30 @@ impl IOCompositor {
|
|||
}
|
||||
|
||||
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(
|
||||
webview_id,
|
||||
pipeline_id,
|
||||
|
|
|
@ -57,6 +57,7 @@ mod from_constellation {
|
|||
Self::GetClientWindowRect(..) => target!("GetClientWindowRect"),
|
||||
Self::GetScreenSize(..) => target!("GetScreenSize"),
|
||||
Self::GetAvailableScreenSize(..) => target!("GetAvailableScreenSize"),
|
||||
Self::CollectMemoryReport(..) => target!("CollectMemoryReport"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ serde = { workspace = true }
|
|||
servo-media = { workspace = true }
|
||||
servo-media-dummy = { workspace = true }
|
||||
servo-media-gstreamer = { workspace = true, optional = true }
|
||||
servo_allocator = { path = "../allocator" }
|
||||
servo_config = { path = "../config" }
|
||||
servo_geometry = { path = "../geometry" }
|
||||
servo_url = { path = "../url" }
|
||||
|
|
|
@ -373,6 +373,7 @@ impl Servo {
|
|||
clear_color,
|
||||
upload_method,
|
||||
workers,
|
||||
size_of_op: Some(servo_allocator::usable_size),
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
|
|
|
@ -27,6 +27,7 @@ image = { workspace = true }
|
|||
ipc-channel = { workspace = true }
|
||||
log = { workspace = true }
|
||||
pixels = { path = '../../pixels' }
|
||||
profile_traits = { path = '../profile' }
|
||||
raw-window-handle = { version = "0.6" }
|
||||
serde = { workspace = true }
|
||||
servo_geometry = { path = "../../geometry" }
|
||||
|
|
|
@ -29,6 +29,7 @@ use display_list::CompositorDisplayListInfo;
|
|||
use embedder_traits::{CompositorHitTestResult, ScreenGeometry};
|
||||
use euclid::default::Size2D as UntypedSize2D;
|
||||
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||
use profile_traits::mem::{OpaqueSender, ReportsChan};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
|
||||
use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect};
|
||||
|
@ -50,6 +51,12 @@ pub struct CompositorProxy {
|
|||
pub event_loop_waker: Box<dyn EventLoopWaker>,
|
||||
}
|
||||
|
||||
impl OpaqueSender<CompositorMsg> for CompositorProxy {
|
||||
fn send(&self, message: CompositorMsg) {
|
||||
CompositorProxy::send(self, message)
|
||||
}
|
||||
}
|
||||
|
||||
impl CompositorProxy {
|
||||
pub fn send(&self, msg: CompositorMsg) {
|
||||
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
|
||||
/// the client window inhabits.
|
||||
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 {
|
||||
|
|
|
@ -50,6 +50,21 @@ where
|
|||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
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 {
|
||||
/// Send `msg` on this `IpcSender`.
|
||||
///
|
||||
|
@ -60,15 +75,15 @@ impl ProfilerChan {
|
|||
}
|
||||
}
|
||||
|
||||
/// Runs `f()` with memory profiling.
|
||||
pub fn run_with_memory_reporting<F, M, T, C>(
|
||||
/// Register a new reporter and return a handle to automatically
|
||||
/// unregister it in the future.
|
||||
pub fn prepare_memory_reporting<M, T, C>(
|
||||
&self,
|
||||
f: F,
|
||||
reporter_name: String,
|
||||
channel_for_reporter: C,
|
||||
msg: M,
|
||||
) where
|
||||
F: FnOnce(),
|
||||
) -> ProfilerRegistration
|
||||
where
|
||||
M: Fn(ReportsChan) -> T + Send + 'static,
|
||||
T: Send + 'static,
|
||||
C: OpaqueSender<T> + Send + 'static,
|
||||
|
@ -88,9 +103,28 @@ impl ProfilerChan {
|
|||
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