Plumb time profiler output into tracing (#34238)

* Plumb time profiler output into tracing

Signed-off-by: Delan Azabani <dazabani@igalia.com>

* Enter the span tightly around the callback

Signed-off-by: Delan Azabani <dazabani@igalia.com>

* Use `info_span!()` shorthand

Signed-off-by: Delan Azabani <dazabani@igalia.com>

---------

Signed-off-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
Delan Azabani 2024-11-15 17:10:01 +08:00 committed by GitHub
parent 495cceb7de
commit aa7116c75d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 279 additions and 82 deletions

4
Cargo.lock generated
View file

@ -3832,6 +3832,7 @@ dependencies = [
"smallvec", "smallvec",
"style", "style",
"style_traits", "style_traits",
"tracing",
"unicode-bidi", "unicode-bidi",
"unicode-script", "unicode-script",
"webrender_api", "webrender_api",
@ -3919,6 +3920,7 @@ dependencies = [
"style", "style",
"style_traits", "style_traits",
"time 0.3.36", "time 0.3.36",
"tracing",
"url", "url",
"webrender_api", "webrender_api",
"webrender_traits", "webrender_traits",
@ -5564,6 +5566,7 @@ dependencies = [
"servo_config", "servo_config",
"signpost", "signpost",
"time 0.3.36", "time 0.3.36",
"tracing",
] ]
[[package]] [[package]]
@ -6074,6 +6077,7 @@ dependencies = [
"tempfile", "tempfile",
"tendril", "tendril",
"time 0.3.36", "time 0.3.36",
"tracing",
"unicode-bidi", "unicode-bidi",
"unicode-segmentation", "unicode-segmentation",
"url", "url",

View file

@ -27,7 +27,8 @@ use ipc_channel::ipc::{self, IpcSharedMemory};
use libc::c_void; use libc::c_void;
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use pixels::{CorsStatus, Image, PixelFormat}; use pixels::{CorsStatus, Image, PixelFormat};
use profile_traits::time::{self as profile_time, profile, ProfilerCategory}; use profile_traits::time::{self as profile_time, ProfilerCategory};
use profile_traits::time_profile;
use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchEvent, WheelEvent}; use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchEvent, WheelEvent};
use script_traits::{ use script_traits::{
AnimationState, AnimationTickType, ConstellationControlMsg, MouseButton, MouseEventType, AnimationState, AnimationTickType, ConstellationControlMsg, MouseButton, MouseEventType,
@ -2098,7 +2099,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.assert_gl_framebuffer_complete(); self.assert_gl_framebuffer_complete();
} }
profile( time_profile!(
ProfilerCategory::Compositing, ProfilerCategory::Compositing,
None, None,
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -2214,7 +2215,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}) })
}, },
CompositeTarget::PngFile(path) => { CompositeTarget::PngFile(path) => {
profile( time_profile!(
ProfilerCategory::ImageSaving, ProfilerCategory::ImageSaving,
None, None,
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),

View file

@ -13,6 +13,9 @@ path = "lib.rs"
test = true test = true
doctest = false doctest = false
[features]
tracing = ["dep:tracing"]
[dependencies] [dependencies]
app_units = { workspace = true } app_units = { workspace = true }
atomic_refcell = { workspace = true } atomic_refcell = { workspace = true }
@ -47,6 +50,7 @@ servo_url = { path = "../url" }
smallvec = { workspace = true, features = ["union"] } smallvec = { workspace = true, features = ["union"] }
style = { workspace = true } style = { workspace = true }
style_traits = { workspace = true } style_traits = { workspace = true }
tracing = { workspace = true, optional = true }
unicode-bidi = { workspace = true, features = ["with_serde"] } unicode-bidi = { workspace = true, features = ["with_serde"] }
unicode-script = { workspace = true } unicode-script = { workspace = true }
webrender_api = { workspace = true } webrender_api = { workspace = true }

View file

@ -11,7 +11,8 @@
use std::sync::atomic::{AtomicIsize, Ordering}; use std::sync::atomic::{AtomicIsize, Ordering};
use std::{mem, ptr}; use std::{mem, ptr};
use profile_traits::time::{self, profile, TimerMetadata}; use profile_traits::time::{self, TimerMetadata};
use profile_traits::time_profile;
use servo_config::opts; use servo_config::opts;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -229,7 +230,7 @@ pub fn reflow(
queue.install(move || { queue.install(move || {
rayon::scope_fifo(move |scope| { rayon::scope_fifo(move |scope| {
profile( time_profile!(
time::ProfilerCategory::LayoutParallelWarmup, time::ProfilerCategory::LayoutParallelWarmup,
profiler_metadata, profiler_metadata,
time_profiler_chan, time_profiler_chan,

View file

@ -11,6 +11,9 @@ rust-version.workspace = true
name = "layout_thread_2013" name = "layout_thread_2013"
path = "lib.rs" path = "lib.rs"
[features]
tracing = ["dep:tracing", "layout/tracing"]
[dependencies] [dependencies]
app_units = { workspace = true } app_units = { workspace = true }
base = { workspace = true } base = { workspace = true }
@ -42,6 +45,7 @@ servo_url = { path = "../url" }
style = { workspace = true } style = { workspace = true }
style_traits = { workspace = true } style_traits = { workspace = true }
time_03 = { workspace = true } time_03 = { workspace = true }
tracing = { workspace = true, optional = true }
url = { workspace = true } url = { workspace = true }
webrender_api = { workspace = true } webrender_api = { workspace = true }
webrender_traits = { workspace = true } webrender_traits = { workspace = true }

View file

@ -55,10 +55,10 @@ use net_traits::image_cache::{ImageCache, UsePlaceholder};
use net_traits::ResourceThreads; use net_traits::ResourceThreads;
use parking_lot::RwLock; use parking_lot::RwLock;
use profile_traits::mem::{Report, ReportKind}; use profile_traits::mem::{Report, ReportKind};
use profile_traits::path;
use profile_traits::time::{ use profile_traits::time::{
self as profile_time, profile, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType, self as profile_time, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
}; };
use profile_traits::{path, time_profile};
use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::wrapper_traits::LayoutNode;
use script_layout_interface::{ use script_layout_interface::{
@ -528,7 +528,7 @@ impl Layout for LayoutThread {
fn reflow(&mut self, script_reflow: script_layout_interface::ScriptReflow) { fn reflow(&mut self, script_reflow: script_layout_interface::ScriptReflow) {
let mut result = ScriptReflowResult::new(script_reflow); let mut result = ScriptReflowResult::new(script_reflow);
profile( time_profile!(
profile_time::ProfilerCategory::LayoutPerform, profile_time::ProfilerCategory::LayoutPerform,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -838,7 +838,7 @@ impl LayoutThread {
) { ) {
let writing_mode = layout_root.base().writing_mode; let writing_mode = layout_root.base().writing_mode;
let (metadata, sender) = (self.profiler_metadata(), self.time_profiler_chan.clone()); let (metadata, sender) = (self.profiler_metadata(), self.time_profiler_chan.clone());
profile( time_profile!(
profile_time::ProfilerCategory::LayoutDispListBuild, profile_time::ProfilerCategory::LayoutDispListBuild,
metadata.clone(), metadata.clone(),
sender.clone(), sender.clone(),
@ -1103,7 +1103,7 @@ impl LayoutThread {
if token.should_traverse() { if token.should_traverse() {
// Recalculate CSS styles and rebuild flows and fragments. // Recalculate CSS styles and rebuild flows and fragments.
profile( time_profile!(
profile_time::ProfilerCategory::LayoutStyleRecalc, profile_time::ProfilerCategory::LayoutStyleRecalc,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -1248,7 +1248,7 @@ impl LayoutThread {
FlowRef::deref_mut(root_flow), FlowRef::deref_mut(root_flow),
); );
profile( time_profile!(
profile_time::ProfilerCategory::LayoutRestyleDamagePropagation, profile_time::ProfilerCategory::LayoutRestyleDamagePropagation,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -1270,7 +1270,7 @@ impl LayoutThread {
} }
// Resolve generated content. // Resolve generated content.
profile( time_profile!(
profile_time::ProfilerCategory::LayoutGeneratedContent, profile_time::ProfilerCategory::LayoutGeneratedContent,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -1278,7 +1278,7 @@ impl LayoutThread {
); );
// Guess float placement. // Guess float placement.
profile( time_profile!(
profile_time::ProfilerCategory::LayoutFloatPlacementSpeculation, profile_time::ProfilerCategory::LayoutFloatPlacementSpeculation,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -1292,7 +1292,7 @@ impl LayoutThread {
.restyle_damage .restyle_damage
.intersects(ServoRestyleDamage::REFLOW | ServoRestyleDamage::REFLOW_OUT_OF_FLOW) .intersects(ServoRestyleDamage::REFLOW | ServoRestyleDamage::REFLOW_OUT_OF_FLOW)
{ {
profile( time_profile!(
profile_time::ProfilerCategory::LayoutMain, profile_time::ProfilerCategory::LayoutMain,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -1316,7 +1316,7 @@ impl LayoutThread {
); );
} }
profile( time_profile!(
profile_time::ProfilerCategory::LayoutStoreOverflow, profile_time::ProfilerCategory::LayoutStoreOverflow,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),

View file

@ -43,10 +43,10 @@ use net_traits::image_cache::{ImageCache, UsePlaceholder};
use net_traits::ResourceThreads; use net_traits::ResourceThreads;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use profile_traits::mem::{Report, ReportKind}; use profile_traits::mem::{Report, ReportKind};
use profile_traits::path;
use profile_traits::time::{ use profile_traits::time::{
self as profile_time, profile, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType, self as profile_time, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
}; };
use profile_traits::{path, time_profile};
use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
use script_layout_interface::{ use script_layout_interface::{
Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse,
@ -500,7 +500,7 @@ impl Layout for LayoutThread {
fn reflow(&mut self, script_reflow: ScriptReflow) { fn reflow(&mut self, script_reflow: ScriptReflow) {
let mut result = ScriptReflowResult::new(script_reflow); let mut result = ScriptReflowResult::new(script_reflow);
profile( time_profile!(
profile_time::ProfilerCategory::LayoutPerform, profile_time::ProfilerCategory::LayoutPerform,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),

View file

@ -16,6 +16,7 @@ path = "lib.rs"
debugmozjs = ['js/debugmozjs'] debugmozjs = ['js/debugmozjs']
jitspew = ['js/jitspew'] jitspew = ['js/jitspew']
profilemozjs = ['js/profilemozjs'] profilemozjs = ['js/profilemozjs']
tracing = ["dep:tracing"]
webgl_backtrace = ["canvas_traits/webgl_backtrace"] webgl_backtrace = ["canvas_traits/webgl_backtrace"]
js_backtrace = [] js_backtrace = []
refcell_backtrace = ["accountable-refcell"] refcell_backtrace = ["accountable-refcell"]
@ -111,6 +112,7 @@ swapper = "0.1"
tempfile = "3" tempfile = "3"
tendril = { version = "0.4.1", features = ["encoding_rs"] } tendril = { version = "0.4.1", features = ["encoding_rs"] }
time_03 = { workspace = true } time_03 = { workspace = true }
tracing = { workspace = true, optional = true }
unicode-bidi = { workspace = true } unicode-bidi = { workspace = true }
unicode-segmentation = { workspace = true } unicode-segmentation = { workspace = true }
url = { workspace = true } url = { workspace = true }

View file

@ -52,7 +52,7 @@ use net_traits::{
fetch_async, CoreResourceMsg, CoreResourceThread, FetchResponseListener, IpcSend, fetch_async, CoreResourceMsg, CoreResourceThread, FetchResponseListener, IpcSend,
ReferrerPolicy, ResourceThreads, ReferrerPolicy, ResourceThreads,
}; };
use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time}; use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time, time_profile};
use script_traits::serializable::{BlobData, BlobImpl, FileBlob}; use script_traits::serializable::{BlobData, BlobImpl, FileBlob};
use script_traits::transferable::MessagePortImpl; use script_traits::transferable::MessagePortImpl;
use script_traits::{ use script_traits::{
@ -2686,7 +2686,7 @@ impl GlobalScope {
iframe: profile_time::TimerMetadataFrameType::RootWindow, iframe: profile_time::TimerMetadataFrameType::RootWindow,
incremental: profile_time::TimerMetadataReflowType::FirstReflow, incremental: profile_time::TimerMetadataReflowType::FirstReflow,
}; };
profile_time::profile( time_profile!(
profile_time::ProfilerCategory::ScriptEvaluate, profile_time::ProfilerCategory::ScriptEvaluate,
Some(metadata), Some(metadata),
self.time_profiler_chan().clone(), self.time_profiler_chan().clone(),

View file

@ -27,8 +27,9 @@ use net_traits::{
ResourceTimingType, ResourceTimingType,
}; };
use profile_traits::time::{ use profile_traits::time::{
profile, ProfilerCategory, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType, ProfilerCategory, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
}; };
use profile_traits::time_profile;
use script_traits::DocumentActivity; use script_traits::DocumentActivity;
use servo_config::pref; use servo_config::pref;
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -521,17 +522,32 @@ impl ServoParser {
iframe: TimerMetadataFrameType::RootWindow, iframe: TimerMetadataFrameType::RootWindow,
incremental: TimerMetadataReflowType::FirstReflow, incremental: TimerMetadataReflowType::FirstReflow,
}; };
let profiler_category = self.tokenizer.profiler_category(); let profiler_chan = self
profile( .document
profiler_category, .window()
Some(metadata), .upcast::<GlobalScope>()
self.document .time_profiler_chan()
.window() .clone();
.upcast::<GlobalScope>() match self.tokenizer {
.time_profiler_chan() Tokenizer::Html(_) => time_profile!(
.clone(), ProfilerCategory::ScriptParseHTML,
|| self.do_parse_sync(can_gc), Some(metadata),
) profiler_chan,
|| self.do_parse_sync(can_gc),
),
Tokenizer::AsyncHtml(_) => time_profile!(
ProfilerCategory::ScriptParseHTML,
Some(metadata),
profiler_chan,
|| self.do_parse_sync(can_gc),
),
Tokenizer::Xml(_) => time_profile!(
ProfilerCategory::ScriptParseXML,
Some(metadata),
profiler_chan,
|| self.do_parse_sync(can_gc),
),
}
} }
fn do_parse_sync(&self, can_gc: CanGc) { fn do_parse_sync(&self, can_gc: CanGc) {
@ -720,14 +736,6 @@ impl Tokenizer {
Tokenizer::Xml(_) => unimplemented!(), Tokenizer::Xml(_) => unimplemented!(),
} }
} }
fn profiler_category(&self) -> ProfilerCategory {
match *self {
Tokenizer::Html(_) => ProfilerCategory::ScriptParseHTML,
Tokenizer::AsyncHtml(_) => ProfilerCategory::ScriptParseHTML,
Tokenizer::Xml(_) => ProfilerCategory::ScriptParseXML,
}
}
} }
/// The context required for asynchronously fetching a document /// The context required for asynchronously fetching a document

View file

@ -74,7 +74,8 @@ use net_traits::{
}; };
use percent_encoding::percent_decode; use percent_encoding::percent_decode;
use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan}; use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan};
use profile_traits::time::{self as profile_time, profile, ProfilerCategory}; use profile_traits::time::{self as profile_time, ProfilerCategory};
use profile_traits::time_profile;
use script_layout_interface::{ use script_layout_interface::{
node_id_from_scroll_id, LayoutConfig, LayoutFactory, ReflowGoal, ScriptThreadFactory, node_id_from_scroll_id, LayoutConfig, LayoutFactory, ReflowGoal, ScriptThreadFactory,
}; };
@ -2165,48 +2166,126 @@ impl ScriptThread {
self.notify_activity_to_hang_monitor(&category); self.notify_activity_to_hang_monitor(&category);
let start = Instant::now(); let start = Instant::now();
let value = if self.profile_script_events { let value = if self.profile_script_events {
let profiler_cat = match category { let profiler_chan = self.time_profiler_chan.clone();
ScriptThreadEventCategory::AttachLayout => ProfilerCategory::ScriptAttachLayout, match category {
ScriptThreadEventCategory::ConstellationMsg => { ScriptThreadEventCategory::AttachLayout => {
ProfilerCategory::ScriptConstellationMsg time_profile!(ProfilerCategory::ScriptAttachLayout, None, profiler_chan, f)
}, },
ScriptThreadEventCategory::DevtoolsMsg => ProfilerCategory::ScriptDevtoolsMsg, ScriptThreadEventCategory::ConstellationMsg => time_profile!(
ScriptThreadEventCategory::DocumentEvent => ProfilerCategory::ScriptDocumentEvent, ProfilerCategory::ScriptConstellationMsg,
ScriptThreadEventCategory::DomEvent => ProfilerCategory::ScriptDomEvent, None,
ScriptThreadEventCategory::FileRead => ProfilerCategory::ScriptFileRead, profiler_chan,
ScriptThreadEventCategory::FormPlannedNavigation => { f
ProfilerCategory::ScriptPlannedNavigation ),
ScriptThreadEventCategory::DevtoolsMsg => {
time_profile!(ProfilerCategory::ScriptDevtoolsMsg, None, profiler_chan, f)
}, },
ScriptThreadEventCategory::HistoryEvent => ProfilerCategory::ScriptHistoryEvent, ScriptThreadEventCategory::DocumentEvent => time_profile!(
ScriptThreadEventCategory::ImageCacheMsg => ProfilerCategory::ScriptImageCacheMsg, ProfilerCategory::ScriptDocumentEvent,
ScriptThreadEventCategory::InputEvent => ProfilerCategory::ScriptInputEvent, None,
ScriptThreadEventCategory::NetworkEvent => ProfilerCategory::ScriptNetworkEvent, profiler_chan,
ScriptThreadEventCategory::PortMessage => ProfilerCategory::ScriptPortMessage, f
ScriptThreadEventCategory::Resize => ProfilerCategory::ScriptResize, ),
ScriptThreadEventCategory::ScriptEvent => ProfilerCategory::ScriptEvent, ScriptThreadEventCategory::DomEvent => {
ScriptThreadEventCategory::SetScrollState => ProfilerCategory::ScriptSetScrollState, time_profile!(ProfilerCategory::ScriptDomEvent, None, profiler_chan, f)
ScriptThreadEventCategory::UpdateReplacedElement => {
ProfilerCategory::ScriptUpdateReplacedElement
}, },
ScriptThreadEventCategory::StylesheetLoad => ProfilerCategory::ScriptStylesheetLoad, ScriptThreadEventCategory::FileRead => {
ScriptThreadEventCategory::SetViewport => ProfilerCategory::ScriptSetViewport, time_profile!(ProfilerCategory::ScriptFileRead, None, profiler_chan, f)
ScriptThreadEventCategory::TimerEvent => ProfilerCategory::ScriptTimerEvent,
ScriptThreadEventCategory::WebSocketEvent => ProfilerCategory::ScriptWebSocketEvent,
ScriptThreadEventCategory::WorkerEvent => ProfilerCategory::ScriptWorkerEvent,
ScriptThreadEventCategory::WorkletEvent => ProfilerCategory::ScriptWorkletEvent,
ScriptThreadEventCategory::ServiceWorkerEvent => {
ProfilerCategory::ScriptServiceWorkerEvent
}, },
ScriptThreadEventCategory::EnterFullscreen => { ScriptThreadEventCategory::FormPlannedNavigation => time_profile!(
ProfilerCategory::ScriptEnterFullscreen ProfilerCategory::ScriptPlannedNavigation,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::HistoryEvent => {
time_profile!(ProfilerCategory::ScriptHistoryEvent, None, profiler_chan, f)
}, },
ScriptThreadEventCategory::ExitFullscreen => ProfilerCategory::ScriptExitFullscreen, ScriptThreadEventCategory::ImageCacheMsg => time_profile!(
ScriptThreadEventCategory::PerformanceTimelineTask => { ProfilerCategory::ScriptImageCacheMsg,
ProfilerCategory::ScriptPerformanceEvent None,
profiler_chan,
f
),
ScriptThreadEventCategory::InputEvent => {
time_profile!(ProfilerCategory::ScriptInputEvent, None, profiler_chan, f)
}, },
ScriptThreadEventCategory::WebGPUMsg => ProfilerCategory::ScriptWebGPUMsg, ScriptThreadEventCategory::NetworkEvent => {
}; time_profile!(ProfilerCategory::ScriptNetworkEvent, None, profiler_chan, f)
profile(profiler_cat, None, self.time_profiler_chan.clone(), f) },
ScriptThreadEventCategory::PortMessage => {
time_profile!(ProfilerCategory::ScriptPortMessage, None, profiler_chan, f)
},
ScriptThreadEventCategory::Resize => {
time_profile!(ProfilerCategory::ScriptResize, None, profiler_chan, f)
},
ScriptThreadEventCategory::ScriptEvent => {
time_profile!(ProfilerCategory::ScriptEvent, None, profiler_chan, f)
},
ScriptThreadEventCategory::SetScrollState => time_profile!(
ProfilerCategory::ScriptSetScrollState,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::UpdateReplacedElement => time_profile!(
ProfilerCategory::ScriptUpdateReplacedElement,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::StylesheetLoad => time_profile!(
ProfilerCategory::ScriptStylesheetLoad,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::SetViewport => {
time_profile!(ProfilerCategory::ScriptSetViewport, None, profiler_chan, f)
},
ScriptThreadEventCategory::TimerEvent => {
time_profile!(ProfilerCategory::ScriptTimerEvent, None, profiler_chan, f)
},
ScriptThreadEventCategory::WebSocketEvent => time_profile!(
ProfilerCategory::ScriptWebSocketEvent,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::WorkerEvent => {
time_profile!(ProfilerCategory::ScriptWorkerEvent, None, profiler_chan, f)
},
ScriptThreadEventCategory::WorkletEvent => {
time_profile!(ProfilerCategory::ScriptWorkletEvent, None, profiler_chan, f)
},
ScriptThreadEventCategory::ServiceWorkerEvent => time_profile!(
ProfilerCategory::ScriptServiceWorkerEvent,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::EnterFullscreen => time_profile!(
ProfilerCategory::ScriptEnterFullscreen,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::ExitFullscreen => time_profile!(
ProfilerCategory::ScriptExitFullscreen,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::PerformanceTimelineTask => time_profile!(
ProfilerCategory::ScriptPerformanceEvent,
None,
profiler_chan,
f
),
ScriptThreadEventCategory::WebGPUMsg => {
time_profile!(ProfilerCategory::ScriptWebGPUMsg, None, profiler_chan, f)
},
}
} else { } else {
f() f()
}; };

View file

@ -24,7 +24,7 @@ no-wgl = ["mozangle/egl", "mozangle/build_dlls", "surfman/sm-angle-default"]
dynamic_freetype = ["webrender/dynamic_freetype"] dynamic_freetype = ["webrender/dynamic_freetype"]
profilemozjs = ["script/profilemozjs"] profilemozjs = ["script/profilemozjs"]
refcell_backtrace = ["script/refcell_backtrace"] refcell_backtrace = ["script/refcell_backtrace"]
tracing = ["dep:tracing", "compositing/tracing", "constellation/tracing", "fonts/tracing", "layout_thread_2020/tracing"] tracing = ["dep:tracing", "compositing/tracing", "constellation/tracing", "fonts/tracing", "layout_thread_2013/tracing", "layout_thread_2020/tracing", "profile_traits/tracing", "script/tracing"]
webdriver = ["webdriver_server"] webdriver = ["webdriver_server"]
webgl_backtrace = [ webgl_backtrace = [
"script/webgl_backtrace", "script/webgl_backtrace",

View file

@ -11,6 +11,9 @@ rust-version.workspace = true
name = "profile_traits" name = "profile_traits"
path = "lib.rs" path = "lib.rs"
[features]
tracing = ["dep:tracing"]
[dependencies] [dependencies]
base = { workspace = true } base = { workspace = true }
crossbeam-channel = { workspace = true } crossbeam-channel = { workspace = true }
@ -20,3 +23,4 @@ serde = { workspace = true }
servo_config = { path = "../../config" } servo_config = { path = "../../config" }
signpost = { git = "https://github.com/pcwalton/signpost.git" } signpost = { git = "https://github.com/pcwalton/signpost.git" }
time_03 = { workspace = true } time_03 = { workspace = true }
tracing = { workspace = true, optional = true }

View file

@ -7,8 +7,8 @@ use std::io::Error;
use ipc_channel::ipc; use ipc_channel::ipc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::time;
use crate::time::{ProfilerCategory, ProfilerChan}; use crate::time::{ProfilerCategory, ProfilerChan};
use crate::time_profile;
pub struct IpcReceiver<T> pub struct IpcReceiver<T>
where where
@ -23,7 +23,7 @@ where
T: for<'de> Deserialize<'de> + Serialize, T: for<'de> Deserialize<'de> + Serialize,
{ {
pub fn recv(&self) -> Result<T, ipc::IpcError> { pub fn recv(&self) -> Result<T, ipc::IpcError> {
time::profile( time_profile!(
ProfilerCategory::IpcReceiver, ProfilerCategory::IpcReceiver,
None, None,
self.time_profile_chan.clone(), self.time_profile_chan.clone(),
@ -61,7 +61,7 @@ pub struct IpcBytesReceiver {
impl IpcBytesReceiver { impl IpcBytesReceiver {
pub fn recv(&self) -> Result<Vec<u8>, ipc::IpcError> { pub fn recv(&self) -> Result<Vec<u8>, ipc::IpcError> {
time::profile( time_profile!(
ProfilerCategory::IpcBytesReceiver, ProfilerCategory::IpcBytesReceiver,
None, None,
self.time_profile_chan.clone(), self.time_profile_chan.clone(),

View file

@ -11,3 +11,17 @@
pub mod ipc; pub mod ipc;
pub mod mem; pub mod mem;
pub mod time; pub mod time;
/// Measure the given callback with the time profiler and (if enabled) tracing.
///
/// `$category` must be const, because we use it to derive the span name.
#[macro_export]
macro_rules! time_profile {
($category:expr, $meta:expr, $profiler_chan:expr, $($callback:tt)+) => {{
#[cfg(feature = "tracing")]
let span = tracing::info_span!($category.variant_name(), servo_profiling = true);
#[cfg(not(feature = "tracing"))]
let span = ();
$crate::time::profile($category, $meta, $profiler_chan, span, $($callback)+)
}};
}

View file

@ -118,6 +118,71 @@ pub enum ProfilerCategory {
IpcBytesReceiver = 0x84, IpcBytesReceiver = 0x84,
} }
impl ProfilerCategory {
pub const fn variant_name(&self) -> &'static str {
match self {
ProfilerCategory::Compositing => "Compositing",
ProfilerCategory::LayoutPerform => "LayoutPerform",
ProfilerCategory::LayoutStyleRecalc => "LayoutStyleRecalc",
ProfilerCategory::LayoutTextShaping => "LayoutTextShaping",
ProfilerCategory::LayoutRestyleDamagePropagation => "LayoutRestyleDamagePropagation",
ProfilerCategory::LayoutNonIncrementalReset => "LayoutNonIncrementalReset",
ProfilerCategory::LayoutSelectorMatch => "LayoutSelectorMatch",
ProfilerCategory::LayoutTreeBuilder => "LayoutTreeBuilder",
ProfilerCategory::LayoutDamagePropagate => "LayoutDamagePropagate",
ProfilerCategory::LayoutGeneratedContent => "LayoutGeneratedContent",
ProfilerCategory::LayoutDisplayListSorting => "LayoutDisplayListSorting",
ProfilerCategory::LayoutFloatPlacementSpeculation => "LayoutFloatPlacementSpeculation",
ProfilerCategory::LayoutMain => "LayoutMain",
ProfilerCategory::LayoutStoreOverflow => "LayoutStoreOverflow",
ProfilerCategory::LayoutParallelWarmup => "LayoutParallelWarmup",
ProfilerCategory::LayoutDispListBuild => "LayoutDispListBuild",
ProfilerCategory::NetHTTPRequestResponse => "NetHTTPRequestResponse",
ProfilerCategory::PaintingPerTile => "PaintingPerTile",
ProfilerCategory::PaintingPrepBuff => "PaintingPrepBuff",
ProfilerCategory::Painting => "Painting",
ProfilerCategory::ImageDecoding => "ImageDecoding",
ProfilerCategory::ImageSaving => "ImageSaving",
ProfilerCategory::ScriptAttachLayout => "ScriptAttachLayout",
ProfilerCategory::ScriptConstellationMsg => "ScriptConstellationMsg",
ProfilerCategory::ScriptDevtoolsMsg => "ScriptDevtoolsMsg",
ProfilerCategory::ScriptDocumentEvent => "ScriptDocumentEvent",
ProfilerCategory::ScriptDomEvent => "ScriptDomEvent",
ProfilerCategory::ScriptEvaluate => "ScriptEvaluate",
ProfilerCategory::ScriptEvent => "ScriptEvent",
ProfilerCategory::ScriptFileRead => "ScriptFileRead",
ProfilerCategory::ScriptImageCacheMsg => "ScriptImageCacheMsg",
ProfilerCategory::ScriptInputEvent => "ScriptInputEvent",
ProfilerCategory::ScriptNetworkEvent => "ScriptNetworkEvent",
ProfilerCategory::ScriptParseHTML => "ScriptParseHTML",
ProfilerCategory::ScriptPlannedNavigation => "ScriptPlannedNavigation",
ProfilerCategory::ScriptResize => "ScriptResize",
ProfilerCategory::ScriptSetScrollState => "ScriptSetScrollState",
ProfilerCategory::ScriptSetViewport => "ScriptSetViewport",
ProfilerCategory::ScriptTimerEvent => "ScriptTimerEvent",
ProfilerCategory::ScriptStylesheetLoad => "ScriptStylesheetLoad",
ProfilerCategory::ScriptUpdateReplacedElement => "ScriptUpdateReplacedElement",
ProfilerCategory::ScriptWebSocketEvent => "ScriptWebSocketEvent",
ProfilerCategory::ScriptWorkerEvent => "ScriptWorkerEvent",
ProfilerCategory::ScriptServiceWorkerEvent => "ScriptServiceWorkerEvent",
ProfilerCategory::ScriptParseXML => "ScriptParseXML",
ProfilerCategory::ScriptEnterFullscreen => "ScriptEnterFullscreen",
ProfilerCategory::ScriptExitFullscreen => "ScriptExitFullscreen",
ProfilerCategory::ScriptWebVREvent => "ScriptWebVREvent",
ProfilerCategory::ScriptWorkletEvent => "ScriptWorkletEvent",
ProfilerCategory::ScriptPerformanceEvent => "ScriptPerformanceEvent",
ProfilerCategory::ScriptHistoryEvent => "ScriptHistoryEvent",
ProfilerCategory::ScriptPortMessage => "ScriptPortMessage",
ProfilerCategory::ScriptWebGPUMsg => "ScriptWebGPUMsg",
ProfilerCategory::TimeToFirstPaint => "TimeToFirstPaint",
ProfilerCategory::TimeToFirstContentfulPaint => "TimeToFirstContentfulPaint",
ProfilerCategory::TimeToInteractive => "TimeToInteractive",
ProfilerCategory::IpcReceiver => "IpcReceiver",
ProfilerCategory::IpcBytesReceiver => "IpcBytesReceiver",
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] #[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub enum TimerMetadataFrameType { pub enum TimerMetadataFrameType {
RootWindow, RootWindow,
@ -130,10 +195,17 @@ pub enum TimerMetadataReflowType {
FirstReflow, FirstReflow,
} }
#[cfg(feature = "tracing")]
pub type Span = tracing::Span;
#[cfg(not(feature = "tracing"))]
pub type Span = ();
pub fn profile<T, F>( pub fn profile<T, F>(
category: ProfilerCategory, category: ProfilerCategory,
meta: Option<TimerMetadata>, meta: Option<TimerMetadata>,
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
#[cfg(feature = "tracing")] span: Span,
#[cfg(not(feature = "tracing"))] _span: Span,
callback: F, callback: F,
) -> T ) -> T
where where
@ -143,7 +215,11 @@ where
signpost::start(category as u32, &[0, 0, 0, (category as usize) >> 4]); signpost::start(category as u32, &[0, 0, 0, (category as usize) >> 4]);
} }
let start_time = CrossProcessInstant::now(); let start_time = CrossProcessInstant::now();
let val = callback(); let val = {
#[cfg(feature = "tracing")]
let _enter = span.enter();
callback()
};
let end_time = CrossProcessInstant::now(); let end_time = CrossProcessInstant::now();
if opts::get().debug.signpost { if opts::get().debug.signpost {