mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
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:
parent
1f232eb17c
commit
5424479768
26 changed files with 416 additions and 787 deletions
|
@ -36,10 +36,7 @@ use hyper_serde::Serde;
|
|||
use ipc_channel::ipc;
|
||||
use js::rust::{HandleObject, HandleValue};
|
||||
use keyboard_types::{Code, Key, KeyState};
|
||||
use metrics::{
|
||||
InteractiveFlag, InteractiveMetrics, InteractiveWindow, ProfilerMetadataFactory,
|
||||
ProgressiveWebMetric,
|
||||
};
|
||||
use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
|
||||
use mime::{self, Mime};
|
||||
use net_traits::CookieSource::NonHTTP;
|
||||
use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
|
||||
|
@ -51,10 +48,11 @@ use net_traits::{FetchResponseListener, IpcSend, ReferrerPolicy};
|
|||
use num_traits::ToPrimitive;
|
||||
use percent_encoding::percent_decode;
|
||||
use profile_traits::ipc as profile_ipc;
|
||||
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType};
|
||||
use profile_traits::time::TimerMetadataFrameType;
|
||||
use script_layout_interface::{PendingRestyle, TrustedNodeAddress};
|
||||
use script_traits::{
|
||||
AnimationState, AnimationTickType, ConstellationInputEvent, DocumentActivity, ScriptMsg,
|
||||
AnimationState, AnimationTickType, ConstellationInputEvent, DocumentActivity,
|
||||
ProgressiveWebMetricType, ScriptMsg,
|
||||
};
|
||||
use servo_arc::Arc;
|
||||
use servo_config::pref;
|
||||
|
@ -78,6 +76,7 @@ use webrender_traits::CompositorHitTestResult;
|
|||
|
||||
use super::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
|
||||
use super::clipboardevent::ClipboardEventType;
|
||||
use super::performancepainttiming::PerformancePaintTiming;
|
||||
use crate::DomTypes;
|
||||
use crate::animation_timeline::AnimationTimeline;
|
||||
use crate::animations::Animations;
|
||||
|
@ -432,7 +431,7 @@ pub(crate) struct Document {
|
|||
/// See <https://html.spec.whatwg.org/multipage/#form-owner>
|
||||
form_id_listener_map: DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>>>,
|
||||
#[no_trace]
|
||||
interactive_time: DomRefCell<InteractiveMetrics>,
|
||||
interactive_time: DomRefCell<ProgressiveWebMetrics>,
|
||||
#[no_trace]
|
||||
tti_window: DomRefCell<InteractiveWindow>,
|
||||
/// RAII canceller for Fetch
|
||||
|
@ -3010,7 +3009,7 @@ impl Document {
|
|||
// html parsing has finished - set dom content loaded
|
||||
self.interactive_time
|
||||
.borrow()
|
||||
.maybe_set_tti(self, InteractiveFlag::DOMContentLoaded);
|
||||
.maybe_set_tti(InteractiveFlag::DOMContentLoaded);
|
||||
|
||||
// Step 4.2.
|
||||
// TODO: client message queue.
|
||||
|
@ -3095,7 +3094,7 @@ impl Document {
|
|||
.set_navigation_start(navigation_start);
|
||||
}
|
||||
|
||||
pub(crate) fn get_interactive_metrics(&self) -> Ref<InteractiveMetrics> {
|
||||
pub(crate) fn get_interactive_metrics(&self) -> Ref<ProgressiveWebMetrics> {
|
||||
self.interactive_time.borrow()
|
||||
}
|
||||
|
||||
|
@ -3149,10 +3148,10 @@ impl Document {
|
|||
return;
|
||||
}
|
||||
if self.tti_window.borrow().needs_check() {
|
||||
self.get_interactive_metrics().maybe_set_tti(
|
||||
self,
|
||||
InteractiveFlag::TimeToInteractive(self.tti_window.borrow().get_start()),
|
||||
);
|
||||
self.get_interactive_metrics()
|
||||
.maybe_set_tti(InteractiveFlag::TimeToInteractive(
|
||||
self.tti_window.borrow().get_start(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3532,6 +3531,37 @@ impl Document {
|
|||
document.root().notify_intersection_observers(CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
pub(crate) fn handle_paint_metric(
|
||||
&self,
|
||||
metric_type: ProgressiveWebMetricType,
|
||||
metric_value: CrossProcessInstant,
|
||||
first_reflow: bool,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
let metrics = self.interactive_time.borrow();
|
||||
match metric_type {
|
||||
ProgressiveWebMetricType::FirstPaint => {
|
||||
metrics.set_first_paint(metric_value, first_reflow)
|
||||
},
|
||||
ProgressiveWebMetricType::FirstContentfulPaint => {
|
||||
metrics.set_first_contentful_paint(metric_value, first_reflow)
|
||||
},
|
||||
ProgressiveWebMetricType::TimeToInteractive => {
|
||||
unreachable!("Unexpected non-paint metric.")
|
||||
},
|
||||
}
|
||||
|
||||
let entry = PerformancePaintTiming::new(
|
||||
self.window.as_global_scope(),
|
||||
metric_type,
|
||||
metric_value,
|
||||
can_gc,
|
||||
);
|
||||
self.window
|
||||
.Performance()
|
||||
.queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_character_value_key(key: &Key) -> bool {
|
||||
|
@ -3688,8 +3718,15 @@ impl Document {
|
|||
(DocumentReadyState::Complete, true)
|
||||
};
|
||||
|
||||
let interactive_time =
|
||||
InteractiveMetrics::new(window.time_profiler_chan().clone(), url.clone());
|
||||
let frame_type = match window.is_top_level() {
|
||||
true => TimerMetadataFrameType::RootWindow,
|
||||
false => TimerMetadataFrameType::IFrame,
|
||||
};
|
||||
let interactive_time = ProgressiveWebMetrics::new(
|
||||
window.time_profiler_chan().clone(),
|
||||
url.clone(),
|
||||
frame_type,
|
||||
);
|
||||
|
||||
let content_type = content_type.unwrap_or_else(|| {
|
||||
match is_html_document {
|
||||
|
@ -4704,16 +4741,6 @@ impl Document {
|
|||
}
|
||||
}
|
||||
|
||||
impl ProfilerMetadataFactory for Document {
|
||||
fn new_metadata(&self) -> Option<TimerMetadata> {
|
||||
Some(TimerMetadata {
|
||||
url: String::from(self.url().as_str()),
|
||||
iframe: TimerMetadataFrameType::RootWindow,
|
||||
incremental: TimerMetadataReflowType::Incremental,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl DocumentMethods<crate::DomTypeHolder> for Document {
|
||||
// https://dom.spec.whatwg.org/#dom-document-document
|
||||
|
|
|
@ -18,7 +18,7 @@ use net_traits::FetchResponseMsg;
|
|||
use net_traits::image_cache::PendingImageResponse;
|
||||
use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan};
|
||||
use profile_traits::time::{self as profile_time};
|
||||
use script_traits::{LayoutMsg, Painter, ScriptMsg, ScriptThreadMessage};
|
||||
use script_traits::{Painter, ScriptMsg, ScriptThreadMessage};
|
||||
use stylo_atoms::Atom;
|
||||
use timers::TimerScheduler;
|
||||
#[cfg(feature = "webgpu")]
|
||||
|
@ -88,7 +88,6 @@ impl MixedMessage {
|
|||
#[cfg(feature = "webgpu")]
|
||||
ScriptThreadMessage::SetWebGPUPort(..) => None,
|
||||
ScriptThreadMessage::SetScrollStates(id, ..) => Some(*id),
|
||||
ScriptThreadMessage::SetEpochPaintTime(id, ..) => Some(*id),
|
||||
},
|
||||
MixedMessage::FromScript(inner_msg) => match inner_msg {
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, _, pipeline_id, _)) => {
|
||||
|
@ -318,10 +317,6 @@ pub(crate) struct ScriptThreadSenders {
|
|||
#[no_trace]
|
||||
pub(crate) pipeline_to_constellation_sender: IpcSender<(PipelineId, ScriptMsg)>,
|
||||
|
||||
/// A sender for layout to communicate to the constellation.
|
||||
#[no_trace]
|
||||
pub(crate) layout_to_constellation_ipc_sender: IpcSender<LayoutMsg>,
|
||||
|
||||
/// The shared [`IpcSender`] which is sent to the `ImageCache` when requesting an image. The
|
||||
/// messages on this channel are routed to crossbeam [`Sender`] on the router thread, which
|
||||
/// in turn sends messages to [`ScriptThreadReceivers::image_cache_receiver`].
|
||||
|
|
|
@ -33,7 +33,6 @@ use background_hang_monitor_api::{
|
|||
BackgroundHangMonitor, BackgroundHangMonitorExitSignal, HangAnnotation, MonitoredComponentId,
|
||||
MonitoredComponentType,
|
||||
};
|
||||
use base::Epoch;
|
||||
use base::cross_process_instant::CrossProcessInstant;
|
||||
use base::id::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespace, WebViewId};
|
||||
use canvas_traits::webgl::WebGLPipeline;
|
||||
|
@ -60,7 +59,7 @@ use js::jsapi::{
|
|||
use js::jsval::UndefinedValue;
|
||||
use js::rust::ParentRuntime;
|
||||
use media::WindowGLContext;
|
||||
use metrics::{MAX_TASK_NS, PaintTimeMetrics};
|
||||
use metrics::MAX_TASK_NS;
|
||||
use mime::{self, Mime};
|
||||
use net_traits::image_cache::{ImageCache, PendingImageResponse};
|
||||
use net_traits::request::{Referrer, RequestId};
|
||||
|
@ -128,8 +127,6 @@ use crate::dom::htmliframeelement::HTMLIFrameElement;
|
|||
use crate::dom::htmlslotelement::HTMLSlotElement;
|
||||
use crate::dom::mutationobserver::MutationObserver;
|
||||
use crate::dom::node::{Node, NodeTraits, ShadowIncluding};
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performancepainttiming::PerformancePaintTiming;
|
||||
use crate::dom::servoparser::{ParserContext, ServoParser};
|
||||
#[cfg(feature = "webgpu")]
|
||||
use crate::dom::webgpu::identityhub::IdentityHub;
|
||||
|
@ -896,7 +893,6 @@ impl ScriptThread {
|
|||
bluetooth_sender: state.bluetooth_sender,
|
||||
constellation_sender: state.constellation_sender,
|
||||
pipeline_to_constellation_sender: state.pipeline_to_constellation_sender.sender.clone(),
|
||||
layout_to_constellation_ipc_sender: state.layout_to_constellation_ipc_sender,
|
||||
image_cache_sender: ipc_image_cache_sender,
|
||||
time_profiler_sender: state.time_profiler_sender,
|
||||
memory_profiler_sender: state.memory_profiler_sender,
|
||||
|
@ -1849,9 +1845,18 @@ impl ScriptThread {
|
|||
ScriptThreadMessage::ExitPipeline(pipeline_id, discard_browsing_context) => {
|
||||
self.handle_exit_pipeline_msg(pipeline_id, discard_browsing_context, can_gc)
|
||||
},
|
||||
ScriptThreadMessage::PaintMetric(pipeline_id, metric_type, metric_value) => {
|
||||
self.handle_paint_metric(pipeline_id, metric_type, metric_value, can_gc)
|
||||
},
|
||||
ScriptThreadMessage::PaintMetric(
|
||||
pipeline_id,
|
||||
metric_type,
|
||||
metric_value,
|
||||
first_reflow,
|
||||
) => self.handle_paint_metric(
|
||||
pipeline_id,
|
||||
metric_type,
|
||||
metric_value,
|
||||
first_reflow,
|
||||
can_gc,
|
||||
),
|
||||
ScriptThreadMessage::MediaSessionAction(pipeline_id, action) => {
|
||||
self.handle_media_session_action(pipeline_id, action, can_gc)
|
||||
},
|
||||
|
@ -1872,9 +1877,6 @@ impl ScriptThread {
|
|||
ScriptThreadMessage::SetScrollStates(pipeline_id, scroll_states) => {
|
||||
self.handle_set_scroll_states_offsets(pipeline_id, scroll_states)
|
||||
},
|
||||
ScriptThreadMessage::SetEpochPaintTime(pipeline_id, epoch, time) => {
|
||||
self.handle_set_epoch_paint_time(pipeline_id, epoch, time)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1910,19 +1912,6 @@ impl ScriptThread {
|
|||
)
|
||||
}
|
||||
|
||||
fn handle_set_epoch_paint_time(
|
||||
&self,
|
||||
pipeline_id: PipelineId,
|
||||
epoch: Epoch,
|
||||
time: CrossProcessInstant,
|
||||
) {
|
||||
let Some(window) = self.documents.borrow().find_window(pipeline_id) else {
|
||||
warn!("Received set epoch paint time message for closed pipeline {pipeline_id}.");
|
||||
return;
|
||||
};
|
||||
window.layout_mut().set_epoch_paint_time(epoch, time);
|
||||
}
|
||||
|
||||
#[cfg(feature = "webgpu")]
|
||||
fn handle_msg_from_webgpu_server(&self, msg: WebGPUMsg, can_gc: CanGc) {
|
||||
match msg {
|
||||
|
@ -3056,16 +3045,6 @@ impl ScriptThread {
|
|||
pipeline_id: incomplete.pipeline_id,
|
||||
};
|
||||
|
||||
let paint_time_metrics = PaintTimeMetrics::new(
|
||||
incomplete.webview_id,
|
||||
incomplete.pipeline_id,
|
||||
self.senders.time_profiler_sender.clone(),
|
||||
self.senders.layout_to_constellation_ipc_sender.clone(),
|
||||
self.senders.constellation_sender.clone(),
|
||||
final_url.clone(),
|
||||
incomplete.navigation_start,
|
||||
);
|
||||
|
||||
let font_context = Arc::new(FontContext::new(
|
||||
self.system_font_service.clone(),
|
||||
self.compositor_api.clone(),
|
||||
|
@ -3082,7 +3061,6 @@ impl ScriptThread {
|
|||
font_context: font_context.clone(),
|
||||
time_profiler_chan: self.senders.time_profiler_sender.clone(),
|
||||
compositor_api: self.compositor_api.clone(),
|
||||
paint_time_metrics,
|
||||
window_size: incomplete.window_size,
|
||||
};
|
||||
|
||||
|
@ -3619,19 +3597,16 @@ impl ScriptThread {
|
|||
pipeline_id: PipelineId,
|
||||
metric_type: ProgressiveWebMetricType,
|
||||
metric_value: CrossProcessInstant,
|
||||
first_reflow: bool,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
let window = self.documents.borrow().find_window(pipeline_id);
|
||||
if let Some(window) = window {
|
||||
let entry = PerformancePaintTiming::new(
|
||||
window.as_global_scope(),
|
||||
metric_type,
|
||||
metric_value,
|
||||
can_gc,
|
||||
);
|
||||
window
|
||||
.Performance()
|
||||
.queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
|
||||
match self.documents.borrow().find_document(pipeline_id) {
|
||||
Some(document) => {
|
||||
document.handle_paint_metric(metric_type, metric_value, first_reflow, can_gc)
|
||||
},
|
||||
None => warn!(
|
||||
"Received paint metric ({metric_type:?}) for unknown document: {pipeline_id:?}"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue