Skip to content

Instantly share code, notes, and snippets.

@jrmuizel
Created May 5, 2025 14:37
Show Gist options
  • Select an option

  • Save jrmuizel/c11b535444192a01dc621213312f9d8a to your computer and use it in GitHub Desktop.

Select an option

Save jrmuizel/c11b535444192a01dc621213312f9d8a to your computer and use it in GitHub Desktop.
commit 815f5a4bd71cdd73dad134125dde89c8e6ec45bd
Author: Jeff Muizelaar <jmuizelaar@mozilla.com>
Date: Fri Nov 15 10:38:17 2024 +0100
Rust flow
diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp
index e6bba66b6fff9..ee6fc53401720 100644
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -73,20 +73,26 @@
using namespace mozilla::net;
namespace mozilla::net {
//-----------------------------------------------------------------------------
// nsHttpTransaction <public>
//-----------------------------------------------------------------------------
nsHttpTransaction::nsHttpTransaction() {
LOG(("Creating nsHttpTransaction @%p\n", this));
+ profiler_add_marker(
+ mozilla::ProfilerString8View::WrapNullTerminatedString("nsHTTPTransaction"),
+ mozilla::baseprofiler::category::NETWORK,
+ {mozilla::MarkerTiming::InstantNow(),
+ },
+ FlowMarker{}, Flow::FromPointer(this));
#ifdef MOZ_VALGRIND
memset(&mSelfAddr, 0, sizeof(NetAddr));
memset(&mPeerAddr, 0, sizeof(NetAddr));
#endif
mSelfAddr.raw.family = PR_AF_UNSPEC;
mPeerAddr.raw.family = PR_AF_UNSPEC;
}
void nsHttpTransaction::ResumeReading() {
diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs
index 761c04e90c630..59e1740579042 100644
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -160,20 +160,24 @@ use style::values::generics::easing::BeforeFlag;
use style::values::generics::length::AnchorResolutionResult;
use style::values::resolved;
use style::values::specified::intersection_observer::IntersectionObserverMargin;
use style::values::specified::source_size_list::SourceSizeList;
use style::values::specified::{AbsoluteLength, NoCalcLength};
use style::values::{specified, AtomIdent, CustomIdent, KeyframesName};
use style::values::specified::svg_path::PathCommand;
use style_traits::{CssWriter, ParseError, ParsingMode, ToCss};
use thin_vec::ThinVec as nsTArray;
use to_shmem::SharedMemoryBuilder;
+use gecko_profiler::Flow;
+use gecko_profiler::MarkerOptions;
+use gecko_profiler::MarkerStack;
+
trait ClosureHelper {
fn invoke(&self, property_id: Option<NonCustomPropertyId>);
}
const NO_MUTATION_CLOSURE : DeclarationBlockMutationClosure = DeclarationBlockMutationClosure {
data: std::ptr::null_mut(),
function: None,
};
@@ -1673,35 +1677,46 @@ pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
mode: SheetParsingMode,
quirks_mode: nsCompatibility,
should_record_use_counters: bool,
allow_import_rules: AllowImportRules,
) {
let load_data = RefPtr::new(load_data);
let extra_data = UrlExtraData::new(extra_data);
let mut sheet_bytes = nsCString::new();
sheet_bytes.assign(bytes);
+ // we use the sheet_bytes allocation as our flow marker
+ let sheet_bytes_flow = Flow::from_pointer(sheet_bytes.as_ref().as_ptr());
let async_parser = AsyncStylesheetParser::new(
load_data,
extra_data,
sheet_bytes,
mode_to_origin(mode),
quirks_mode.into(),
should_record_use_counters,
allow_import_rules,
);
+ gecko_profiler::add_marker("StyleParseQueue",
+ gecko_profiler::gecko_profiler_category!(Layout),
+ MarkerOptions { timing: Default::default(), stack: MarkerStack::Full },
+ sheet_bytes_flow);
if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
- thread_pool.spawn(|| {
+ thread_pool.spawn(move || {
gecko_profiler_label!(Layout, CSSParsing);
+ auto_profiler_flow_marker!("StyleParseDo",
+ gecko_profiler::gecko_profiler_category!(Graphics),
+ Default::default(),
+ sheet_bytes_flow);
async_parser.parse();
+
});
} else {
async_parser.parse();
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
debug_assert!(is_main_thread() && !is_in_servo_traversal());
StyleThreadPool::shutdown();
diff --git a/tools/profiler/core/ProfilerBindings.cpp b/tools/profiler/core/ProfilerBindings.cpp
index 833facba00d87..db326a8c182e2 100644
--- a/tools/profiler/core/ProfilerBindings.cpp
+++ b/tools/profiler/core/ProfilerBindings.cpp
@@ -179,20 +179,26 @@ void gecko_profiler_marker_schema_set_table_label(
}
void gecko_profiler_marker_schema_set_all_labels(mozilla::MarkerSchema* aSchema,
const char* aLabel,
size_t aLabelLength) {
#ifdef MOZ_GECKO_PROFILER
aSchema->SetAllLabels(std::string(aLabel, aLabelLength));
#endif
}
+void gecko_profiler_marker_schema_set_is_stack_based(mozilla::MarkerSchema* aSchema) {
+#ifdef MOZ_GECKO_PROFILER
+ aSchema->SetIsStackBased();
+#endif
+}
+
void gecko_profiler_marker_schema_add_key_format(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
mozilla::MarkerSchema::Format aFormat) {
#ifdef MOZ_GECKO_PROFILER
aSchema->AddKeyFormat(std::string(aKey, aKeyLength), aFormat);
#endif
}
void gecko_profiler_marker_schema_add_key_label_format(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
diff --git a/tools/profiler/public/ProfilerBindings.h b/tools/profiler/public/ProfilerBindings.h
index 3ae6a16206103..3cfe6d02059aa 100644
--- a/tools/profiler/public/ProfilerBindings.h
+++ b/tools/profiler/public/ProfilerBindings.h
@@ -85,20 +85,21 @@ void gecko_profiler_destruct_marker_schema(
// MarkerSchema methods for adding labels.
void gecko_profiler_marker_schema_set_chart_label(
mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength);
void gecko_profiler_marker_schema_set_tooltip_label(
mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength);
void gecko_profiler_marker_schema_set_table_label(
mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength);
void gecko_profiler_marker_schema_set_all_labels(mozilla::MarkerSchema* aSchema,
const char* aLabel,
size_t aLabelLength);
+void gecko_profiler_marker_schema_set_is_stack_based(mozilla::MarkerSchema* aSchema);
// MarkerSchema methods for adding key/key-label values.
void gecko_profiler_marker_schema_add_key_format(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
mozilla::MarkerSchema::Format aFormat);
void gecko_profiler_marker_schema_add_key_label_format(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
const char* aLabel, size_t aLabelLength,
mozilla::MarkerSchema::Format aFormat);
void gecko_profiler_marker_schema_add_key_format_searchable(
diff --git a/tools/profiler/rust-api/src/marker/mod.rs b/tools/profiler/rust-api/src/marker/mod.rs
index 2d796ac8753a9..7e0b34a3ec506 100644
--- a/tools/profiler/rust-api/src/marker/mod.rs
+++ b/tools/profiler/rust-api/src/marker/mod.rs
@@ -538,10 +538,149 @@ macro_rules! auto_profiler_marker_tracing {
};
}
#[cfg(not(feature = "enabled"))]
#[macro_export]
macro_rules! auto_profiler_marker_tracing {
($name:expr, $category:expr,$options:expr, $payload:expr) => {
// Do nothing if the profiler is not enabled
};
}
+
+/// Flow marker type for Rust code.
+/// This must be kept in sync with the `mozilla::baseprofiler::markers::Tracing`
+/// C++ counterpart.
+#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
+pub struct Flow(pub u64);
+
+impl Flow {
+ pub fn from_pointer<T>(s: *const T) -> Self {
+ Flow(s as usize as u64)
+ }
+}
+
+impl ProfilerMarker for Flow {
+ fn marker_type_name() -> &'static str {
+ "flow"
+ }
+
+ fn stream_json_marker_data(&self, json_writer: &mut JSONWriter) {
+
+ fn hex_string(id: u64) -> [u8; 16] {
+ let mut buf = [0; 16];
+ let hex_digits = b"0123456789abcdef";
+ for i in 0..16 {
+ buf[i] = hex_digits[(id >> (60 - i * 4)) as usize & 0xf];
+ }
+ buf
+ }
+
+ json_writer.unique_string_property("flow", unsafe { std::str::from_utf8_unchecked(&hex_string(self.0)) });
+ }
+
+ // Tracing marker is a bit special because we have the same schema in the
+ // C++ side. This function will only get called when no Tracing markers are
+ // generated from the C++ side. But, most of the time, this will not be called
+ // when there is another C++ Tracing marker.
+ fn marker_type_display() -> MarkerSchema {
+ use crate::marker::schema::*;
+ let mut schema = MarkerSchema::new(&[
+ Location::MarkerChart,
+ Location::MarkerTable,
+ Location::TimelineOverview,
+ ]);
+ schema.add_key_label_format("flow", "Type", Format::Flow);
+ schema.set_is_stack_based();
+ schema
+ }
+}
+
+/// RAII-style scoped tracing marker for Rust code.
+/// This is a Rust-style equivalent of the C++ AUTO_PROFILER_TRACING_MARKER
+/// Profiler markers are emitted at when an AutoProfilerFlowMarker is
+/// created, and when it is dropped (destroyed).
+pub struct AutoProfilerFlowMarker<'a> {
+ name: &'a str,
+ category: ProfilingCategoryPair,
+ options: MarkerOptions,
+ flow: Flow,
+}
+
+impl<'a> AutoProfilerFlowMarker<'a> {
+ pub fn new(
+ name: &'a str,
+ category: ProfilingCategoryPair,
+ options: MarkerOptions,
+ flow: Flow,
+ ) -> Option<AutoProfilerFlowMarker<'a>> {
+ if !crate::profiler_state::can_accept_markers() {
+ return None;
+ }
+ // Record our starting marker.
+ add_marker(
+ name,
+ category,
+ options.with_timing(MarkerTiming::interval_start(ProfilerTime::now())),
+ flow,
+ );
+ Some(AutoProfilerFlowMarker {
+ name,
+ category,
+ options,
+ flow,
+ })
+ }
+}
+
+impl<'a> Drop for AutoProfilerFlowMarker<'a> {
+ fn drop(&mut self) {
+ // If we have an AutoProfilerFlowMarker object, then the profiler was
+ // running + accepting markers when it was *created*. We have no
+ // guarantee that it's still running though, so check again! If the
+ // profiler has stopped, then there's no point recording the second of a
+ // pair of markers.
+ if !crate::profiler_state::can_accept_markers() {
+ return;
+ }
+ // record the ending marker
+ add_marker(
+ self.name,
+ self.category,
+ self.options
+ .with_timing(MarkerTiming::interval_end(ProfilerTime::now())),
+ self.flow,
+ );
+ }
+}
+
+/// Create an RAII-style tracing marker. See AutoProfilerFlowMarker for more
+/// details.
+///
+/// The arguments to this macro correspond exactly to the
+/// AutoProfilerFlowMarker::new constructor.
+///
+/// Example usage:
+/// ```rust
+/// auto_profiler_marker_tracing!(
+/// "BlobRasterization",
+/// gecko_profiler_category!(Graphics),
+/// Default::default(),
+/// "Webrender".to_string()
+/// );
+/// ```
+///
+#[cfg(feature = "enabled")]
+#[macro_export]
+macro_rules! auto_profiler_flow_marker {
+ ($name:expr, $category:expr,$options:expr, $payload:expr) => {
+ let _macro_created_rust_tracing_marker =
+ $crate::AutoProfilerFlowMarker::new($name, $category, $options, $payload);
+ };
+}
+
+#[cfg(not(feature = "enabled"))]
+#[macro_export]
+macro_rules! auto_profiler_flow_marker {
+ ($name:expr, $category:expr,$options:expr, $payload:expr) => {
+ // Do nothing if the profiler is not enabled
+ };
+}
diff --git a/tools/profiler/rust-api/src/marker/schema.rs b/tools/profiler/rust-api/src/marker/schema.rs
index 984966e7c0821..87845a6ef6178 100644
--- a/tools/profiler/rust-api/src/marker/schema.rs
+++ b/tools/profiler/rust-api/src/marker/schema.rs
@@ -103,20 +103,28 @@ impl MarkerSchema {
unsafe {
bindings::gecko_profiler_marker_schema_set_all_labels(
self.ptr,
label.as_ptr() as *const c_char,
label.len(),
);
}
self
}
+ /// Set the marker to be stack based
+ pub fn set_is_stack_based(&mut self) -> &mut Self {
+ unsafe {
+ bindings::gecko_profiler_marker_schema_set_is_stack_based(self.ptr);
+ }
+ self
+ }
+
// Each data element that is streamed by `stream_json_marker_data()` can be
// displayed as indicated by using one of the `add_...` function below.
// Each `add...` will add a line in the full marker description. Parameters:
// - `key`: Element property name as streamed by `stream_json_marker_data()`.
// - `label`: Optional label. Defaults to the key name.
// - `format`: How to format the data element value, see `Format` above.
// - `searchable`: Optional, indicates if the value is used in searches,
// defaults to false.
/// Add a key / format row for the marker data element.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment