metrics: Simplify ProgressiveWebMetrics (#35985)

Simply how `ProgressiveWebMetrics` works:

1. Keep only a single struct instead of one in layout and one script
   that both implement the `ProgressiveWebMetrics` trait. Since layout
   and script are the same thread these can now just be a single
   `ProgressiveWebMetrics` struct stored in script.
2. Have the compositor be responsible for informing the Constellation
   (which informs the ScripThread) about paint metrics. This makes
   communication flow one way and removes one dependency between the
   compositor and script (of two).
3. All units tests are moved into the `metrics` crate itself since there
   is only one struct there now.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-03-21 15:55:00 +01:00 committed by GitHub
parent 1f232eb17c
commit 5424479768
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 416 additions and 787 deletions

View file

@ -7,6 +7,7 @@ use std::fmt;
use std::time::Duration;
use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{PipelineId, WebViewId};
use embedder_traits::{
Cursor, InputEvent, MediaSessionActionType, Theme, TraversalDirection, WebDriverCommandMsg,
@ -72,6 +73,15 @@ pub enum ConstellationMsg {
/// The Servo renderer scrolled and is updating the scroll states of the nodes in the
/// given pipeline via the constellation.
SetScrollStates(PipelineId, Vec<ScrollState>),
/// Notify the constellation that a particular paint metric event has happened for the given pipeline.
PaintMetric(PipelineId, PaintMetricEvent),
}
/// A description of a paint metric that is sent from the Servo renderer to the
/// constellation.
pub enum PaintMetricEvent {
FirstPaint(CrossProcessInstant, bool /* first_reflow */),
FirstContentfulPaint(CrossProcessInstant, bool /* first_reflow */),
}
impl fmt::Debug for ConstellationMsg {

View file

@ -8,9 +8,8 @@ mod constellation_msg;
use std::fmt::{Debug, Error, Formatter};
use base::Epoch;
use base::id::{PipelineId, WebViewId};
pub use constellation_msg::ConstellationMsg;
pub use constellation_msg::{ConstellationMsg, PaintMetricEvent};
use crossbeam_channel::{Receiver, Sender};
use embedder_traits::{EventLoopWaker, MouseButton, MouseButtonAction};
use euclid::Rect;
@ -84,10 +83,6 @@ pub enum CompositorMsg {
// sends a reply on the IpcSender, the constellation knows it's safe to
// tear down the other threads associated with this pipeline.
PipelineExited(WebViewId, PipelineId, IpcSender<()>),
/// Indicates to the compositor that it needs to record the time when the frame with
/// the given ID (epoch) is painted and report it to the layout of the given
/// WebViewId and PipelienId.
PendingPaintMetric(WebViewId, PipelineId, Epoch),
/// The load of a page has completed
LoadComplete(WebViewId),
/// WebDriver mouse button event

View file

@ -19,6 +19,8 @@ base = { workspace = true }
crossbeam-channel = { workspace = true }
ipc-channel = { workspace = true }
log = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
serde = { workspace = true }
servo_config = { path = "../../config" }
signpost = { git = "https://github.com/pcwalton/signpost.git" }

View file

@ -5,6 +5,7 @@
use base::cross_process_instant::CrossProcessInstant;
use ipc_channel::ipc::IpcSender;
use log::warn;
use malloc_size_of_derive::MallocSizeOf;
use serde::{Deserialize, Serialize};
use servo_config::opts;
use strum_macros::IntoStaticStr;
@ -188,7 +189,7 @@ impl ProfilerCategory {
}
}
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize)]
pub enum TimerMetadataFrameType {
RootWindow,
IFrame,

View file

@ -19,7 +19,6 @@ use std::fmt;
use std::sync::Arc;
use background_hang_monitor_api::BackgroundHangMonitorRegister;
use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{
BlobId, BrowsingContextId, HistoryStateId, MessagePortId, PipelineId, PipelineNamespaceId,
@ -64,9 +63,8 @@ use webrender_traits::{
};
pub use crate::script_msg::{
DOMMessage, IFrameSizeMsg, Job, JobError, JobResult, JobResultValue, JobType, LayoutMsg,
LogEntry, SWManagerMsg, SWManagerSenders, ScopeThings, ScriptMsg, ServiceWorkerMsg,
TouchEventResult,
DOMMessage, IFrameSizeMsg, Job, JobError, JobResult, JobResultValue, JobType, LogEntry,
SWManagerMsg, SWManagerSenders, ScopeThings, ScriptMsg, ServiceWorkerMsg, TouchEventResult,
};
use crate::serializable::BlobImpl;
use crate::transferable::MessagePortImpl;
@ -395,7 +393,12 @@ pub enum ScriptThreadMessage {
/// Reload the given page.
Reload(PipelineId),
/// Notifies the script thread about a new recorded paint metric.
PaintMetric(PipelineId, ProgressiveWebMetricType, CrossProcessInstant),
PaintMetric(
PipelineId,
ProgressiveWebMetricType,
CrossProcessInstant,
bool, /* first_reflow */
),
/// Notifies the media session about a user requested media session action.
MediaSessionAction(PipelineId, MediaSessionActionType),
/// Notifies script thread that WebGPU server has started
@ -404,8 +407,6 @@ pub enum ScriptThreadMessage {
/// The compositor scrolled and is updating the scroll states of the nodes in the given
/// pipeline via the Constellation.
SetScrollStates(PipelineId, Vec<ScrollState>),
/// Send the paint time for a specific epoch.
SetEpochPaintTime(PipelineId, Epoch, CrossProcessInstant),
}
impl fmt::Debug for ScriptThreadMessage {
@ -476,8 +477,6 @@ pub struct InitialScriptState {
pub pipeline_to_constellation_sender: ScriptToConstellationChan,
/// A handle to register script-(and associated layout-)threads for hang monitoring.
pub background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
/// A sender layout to communicate to the constellation.
pub layout_to_constellation_ipc_sender: IpcSender<LayoutMsg>,
/// A channel to the resource manager thread.
pub resource_threads: ResourceThreads,
/// A channel to the bluetooth thread.

View file

@ -46,21 +46,6 @@ pub struct IFrameSizeMsg {
pub type_: WindowSizeType,
}
/// Messages from the layout to the constellation.
#[derive(Deserialize, IntoStaticStr, Serialize)]
pub enum LayoutMsg {
/// Requests that the constellation inform the compositor that it needs to record
/// the time when the frame with the given ID (epoch) is painted.
PendingPaintMetric(WebViewId, PipelineId, Epoch),
}
impl fmt::Debug for LayoutMsg {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let variant_string: &'static str = self.into();
write!(formatter, "LayoutMsg::{variant_string}")
}
}
/// Whether the default action for a touch event was prevented by web content
#[derive(Debug, Deserialize, Serialize)]
pub enum TouchEventResult {

View file

@ -18,7 +18,6 @@ use std::sync::atomic::{AtomicIsize, AtomicU64, Ordering};
use app_units::Au;
use atomic_refcell::AtomicRefCell;
use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{BrowsingContextId, PipelineId, WebViewId};
use canvas_traits::canvas::{CanvasId, CanvasMsg};
use euclid::Size2D;
@ -28,7 +27,6 @@ use fonts::{FontContext, SystemFontServiceProxy};
use ipc_channel::ipc::IpcSender;
use libc::c_void;
use malloc_size_of_derive::MallocSizeOf;
use metrics::PaintTimeMetrics;
use net_traits::image_cache::{ImageCache, PendingImageId};
use profile_traits::mem::Report;
use profile_traits::time;
@ -189,7 +187,6 @@ pub struct LayoutConfig {
pub font_context: Arc<FontContext>,
pub time_profiler_chan: time::ProfilerChan,
pub compositor_api: CrossProcessCompositorApi,
pub paint_time_metrics: PaintTimeMetrics,
pub window_size: WindowSizeData,
}
@ -245,9 +242,6 @@ pub trait Layout {
/// Set the scroll states of this layout after a compositor scroll.
fn set_scroll_offsets(&mut self, scroll_states: &[ScrollState]);
/// Set the paint time for a specific epoch.
fn set_epoch_paint_time(&mut self, epoch: Epoch, paint_time: CrossProcessInstant);
fn query_content_box(&self, node: OpaqueNode) -> Option<Rect<Au>>;
fn query_content_boxes(&self, node: OpaqueNode) -> Vec<Rect<Au>>;
fn query_client_rect(&self, node: OpaqueNode) -> Rect<i32>;

View file

@ -305,6 +305,15 @@ pub struct CompositorDisplayListInfo {
/// The `ScrollTreeNodeId` of the topmost scrolling frame of this info's scroll
/// tree.
pub root_scroll_node_id: ScrollTreeNodeId,
/// Contentful paint i.e. whether the display list contains items of type
/// text, image, non-white canvas or SVG). Used by metrics.
/// See <https://w3c.github.io/paint-timing/#first-contentful-paint>.
pub is_contentful: bool,
/// Whether the first layout or a subsequent (incremental) layout triggered this
/// display list creation.
pub first_reflow: bool,
}
impl CompositorDisplayListInfo {
@ -316,6 +325,7 @@ impl CompositorDisplayListInfo {
pipeline_id: PipelineId,
epoch: Epoch,
viewport_scroll_sensitivity: AxesScrollSensitivity,
first_reflow: bool,
) -> Self {
let mut scroll_tree = ScrollTree::default();
let root_reference_frame_id = scroll_tree.add_scroll_tree_node(
@ -343,6 +353,8 @@ impl CompositorDisplayListInfo {
scroll_tree,
root_reference_frame_id,
root_scroll_node_id,
is_contentful: false,
first_reflow,
}
}