commit a0e172eccc37c27c5bcfb9e8c7291d54c341a29b
parent 2b8042eb00d2e9abc21981185403d875283cf67f
Author: Max Leonard Inden <mail@max-inden.de>
Date: Wed, 29 Oct 2025 13:23:57 +0000
Bug 1968065 - expose Flow Marker API to Rust r=profiler-reviewers,canaltinova
Differential Revision: https://phabricator.services.mozilla.com/D250824
Diffstat:
4 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/tools/profiler/core/ProfilerBindings.cpp b/tools/profiler/core/ProfilerBindings.cpp
@@ -186,6 +186,13 @@ void gecko_profiler_marker_schema_set_all_labels(mozilla::MarkerSchema* aSchema,
#endif
}
+void gecko_profiler_marker_schema_set_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) {
diff --git a/tools/profiler/public/ProfilerBindings.h b/tools/profiler/public/ProfilerBindings.h
@@ -92,6 +92,8 @@ 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);
+void gecko_profiler_marker_schema_set_stack_based(
+ mozilla::MarkerSchema* aSchema);
// MarkerSchema methods for adding key/key-label values.
void gecko_profiler_marker_schema_add_key_format(
diff --git a/tools/profiler/rust-api/src/marker/mod.rs b/tools/profiler/rust-api/src/marker/mod.rs
@@ -545,3 +545,135 @@ macro_rules! auto_profiler_marker_tracing {
// Do nothing if the profiler is not enabled
};
}
+
+/// Flow marker type for Rust code.
+#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
+pub struct FlowStackMarker(pub u64);
+
+impl FlowStackMarker {
+ pub fn from_pointer<T>(s: *const T) -> Self {
+ FlowStackMarker(s.addr() as u64)
+ }
+}
+
+impl ProfilerMarker for FlowStackMarker {
+ fn marker_type_name() -> &'static str {
+ "FlowStackRust"
+ }
+
+ 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))
+ });
+ }
+
+ // Flow marker is a bit special because we have the same schema in the C++
+ // side. This function will only get called when no Flow markers are
+ // generated from the C++ side. But, most of the time, this will not be
+ // called when there is another C++ Flow marker.
+ fn marker_type_display() -> MarkerSchema {
+ use crate::marker::schema::*;
+ let mut schema = MarkerSchema::new(&[Location::MarkerChart, Location::MarkerTable]);
+ schema.add_key_label_format("flow", "Flow", Format::Flow);
+ schema.set_stack_based();
+ schema
+ }
+}
+
+/// RAII-style scoped tracing marker for Rust code.
+/// This is a Rust-style equivalent of the C++ AUTO_PROFILER_FLOW_MARKER
+/// Profiler markers are emitted when an [`AutoProfilerFlowMarker`] is created,
+/// and when it is dropped (destroyed).
+pub struct AutoProfilerFlowMarker<'a> {
+ name: &'a str,
+ category: ProfilingCategoryPair,
+ options: MarkerOptions,
+ flow: FlowStackMarker,
+ // We store the start time separately from the MarkerTiming inside
+ // MarkerOptions, as once we have "put it in" a marker timing, there's
+ // currently no API way to "get it out" again.
+ start: ProfilerTime,
+}
+
+impl<'a> AutoProfilerFlowMarker<'a> {
+ pub fn new(
+ name: &'a str,
+ category: ProfilingCategoryPair,
+ options: MarkerOptions,
+ flow: FlowStackMarker,
+ ) -> Option<AutoProfilerFlowMarker<'a>> {
+ if !crate::profiler_state::can_accept_markers() {
+ return None;
+ }
+ Some(AutoProfilerFlowMarker {
+ name,
+ category,
+ options,
+ flow,
+ start: ProfilerTime::now(),
+ })
+ }
+}
+
+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_until_now_from(self.start.clone())),
+ 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_flow_marker!(
+/// "BlobRasterization",
+/// gecko_profiler_category!(Graphics),
+/// Default::default(),
+/// flow
+/// );
+/// ```
+///
+#[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
@@ -110,6 +110,14 @@ impl MarkerSchema {
self
}
+ /// Set the marker to be stack based
+ pub fn set_stack_based(&mut self) -> &mut Self {
+ unsafe {
+ bindings::gecko_profiler_marker_schema_set_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: