From a5b9cfdadb75914b2eca850f50ac42f310f73777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 21 Sep 2021 11:08:11 +0000 Subject: [PATCH] Bug 1654413 - Add MarkerSchema struct and its enums for marker API r=emilio,gerald You can see the `mozilla::MarkerSchema` for the C++ counterpart. This Rust struct simply wraps the C++ object and keeps the reference of it as RAII. This heap allocates the inner C++ object but it's fine to do it here, because it's we only create a MarkerSchema object at the end of a profiling session and it happens once per marker type. It should be very rare. Differential Revision: https://phabricator.services.mozilla.com/D124025 --- .../public/BaseProfilerMarkersPrerequisites.h | 5 + tools/profiler/core/ProfilerBindings.cpp | 101 ++++++++ tools/profiler/public/ProfilerBindings.h | 44 ++++ tools/profiler/rust-api/build.rs | 7 + tools/profiler/rust-api/src/marker/mod.rs | 1 + tools/profiler/rust-api/src/marker/schema.rs | 233 ++++++++++++++++++ 6 files changed, 391 insertions(+) create mode 100644 tools/profiler/rust-api/src/marker/schema.rs diff --git a/mozglue/baseprofiler/public/BaseProfilerMarkersPrerequisites.h b/mozglue/baseprofiler/public/BaseProfilerMarkersPrerequisites.h index 5b66b8bc78d4..15fd729d0ca8 100644 --- a/mozglue/baseprofiler/public/BaseProfilerMarkersPrerequisites.h +++ b/mozglue/baseprofiler/public/BaseProfilerMarkersPrerequisites.h @@ -760,6 +760,11 @@ class MarkerSchema { explicit MarkerSchema(Location aLocation, Locations... aLocations) : mLocations{aLocation, aLocations...} {} + // Alternative constructor for MarkerSchema. + explicit MarkerSchema(const mozilla::MarkerSchema::Location* aLocations, + size_t aLength) + : mLocations(aLocations, aLocations + aLength) {} + // Marker schema for types that have special frontend handling. // Nothing else should be set in this case. // Implicit to allow quick return from MarkerTypeDisplay functions. diff --git a/tools/profiler/core/ProfilerBindings.cpp b/tools/profiler/core/ProfilerBindings.cpp index 5876c1b43ff0..dda01e1cdcca 100644 --- a/tools/profiler/core/ProfilerBindings.cpp +++ b/tools/profiler/core/ProfilerBindings.cpp @@ -111,6 +111,107 @@ void gecko_profiler_destruct_marker_timing( #endif } +void gecko_profiler_construct_marker_schema( + mozilla::MarkerSchema* aMarkerSchema, + const mozilla::MarkerSchema::Location* aLocations, size_t aLength) { +#ifdef MOZ_GECKO_PROFILER + new (aMarkerSchema) mozilla::MarkerSchema(aLocations, aLength); +#endif +} + +void gecko_profiler_construct_marker_schema_with_special_front_end_location( + mozilla::MarkerSchema* aMarkerSchema) { +#ifdef MOZ_GECKO_PROFILER + new (aMarkerSchema) + mozilla::MarkerSchema(mozilla::MarkerSchema::SpecialFrontendLocation{}); +#endif +} + +void gecko_profiler_destruct_marker_schema( + mozilla::MarkerSchema* aMarkerSchema) { +#ifdef MOZ_GECKO_PROFILER + aMarkerSchema->~MarkerSchema(); +#endif +} + +void gecko_profiler_marker_schema_set_chart_label( + mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength) { +#ifdef MOZ_GECKO_PROFILER + aSchema->SetChartLabel(std::string(aLabel, aLabelLength)); +#endif +} + +void gecko_profiler_marker_schema_set_tooltip_label( + mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength) { +#ifdef MOZ_GECKO_PROFILER + aSchema->SetTooltipLabel(std::string(aLabel, aLabelLength)); +#endif +} + +void gecko_profiler_marker_schema_set_table_label( + mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength) { +#ifdef MOZ_GECKO_PROFILER + aSchema->SetTableLabel(std::string(aLabel, aLabelLength)); +#endif +} + +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_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, + const char* aLabel, size_t aLabelLength, + mozilla::MarkerSchema::Format aFormat) { +#ifdef MOZ_GECKO_PROFILER + aSchema->AddKeyLabelFormat(std::string(aKey, aKeyLength), + std::string(aLabel, aLabelLength), aFormat); +#endif +} + +void gecko_profiler_marker_schema_add_key_format_searchable( + mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength, + mozilla::MarkerSchema::Format aFormat, + mozilla::MarkerSchema::Searchable aSearchable) { +#ifdef MOZ_GECKO_PROFILER + aSchema->AddKeyFormatSearchable(std::string(aKey, aKeyLength), aFormat, + aSearchable); +#endif +} + +void gecko_profiler_marker_schema_add_key_label_format_searchable( + mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength, + const char* aLabel, size_t aLabelLength, + mozilla::MarkerSchema::Format aFormat, + mozilla::MarkerSchema::Searchable aSearchable) { +#ifdef MOZ_GECKO_PROFILER + aSchema->AddKeyLabelFormatSearchable(std::string(aKey, aKeyLength), + std::string(aLabel, aLabelLength), + aFormat, aSearchable); +#endif +} + +void gecko_profiler_marker_schema_add_static_label_value( + mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength, + const char* aValue, size_t aValueLength) { +#ifdef MOZ_GECKO_PROFILER + aSchema->AddStaticLabelValue(std::string(aLabel, aLabelLength), + std::string(aValue, aValueLength)); +#endif +} + void gecko_profiler_json_writer_int_property( mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName, size_t aNameLength, int64_t aValue) { diff --git a/tools/profiler/public/ProfilerBindings.h b/tools/profiler/public/ProfilerBindings.h index 053b4dda682f..d7ff993d5757 100644 --- a/tools/profiler/public/ProfilerBindings.h +++ b/tools/profiler/public/ProfilerBindings.h @@ -9,11 +9,14 @@ #ifndef ProfilerBindings_h #define ProfilerBindings_h +#include "mozilla/BaseProfilerMarkersPrerequisites.h" + #include #include namespace mozilla { class AutoProfilerLabel; +class MarkerSchema; class MarkerTiming; class TimeStamp; enum class StackCaptureOptions; @@ -61,6 +64,47 @@ void gecko_profiler_construct_marker_timing_interval_end( void gecko_profiler_destruct_marker_timing( mozilla::MarkerTiming* aMarkerTiming); +// MarkerSchema constructors and destructor. +void gecko_profiler_construct_marker_schema( + mozilla::MarkerSchema* aMarkerSchema, + const mozilla::MarkerSchema::Location* aLocations, size_t aLength); +void gecko_profiler_construct_marker_schema_with_special_front_end_location( + mozilla::MarkerSchema* aMarkerSchema); +void gecko_profiler_destruct_marker_schema( + mozilla::MarkerSchema* aMarkerSchema); + +// 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); + +// 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( + mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength, + mozilla::MarkerSchema::Format aFormat, + mozilla::MarkerSchema::Searchable aSearchable); +void gecko_profiler_marker_schema_add_key_label_format_searchable( + mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength, + const char* aLabel, size_t aLabelLength, + mozilla::MarkerSchema::Format aFormat, + mozilla::MarkerSchema::Searchable aSearchable); +void gecko_profiler_marker_schema_add_static_label_value( + mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength, + const char* aValue, size_t aValueLength); + // Various SpliceableJSONWriter methods to add properties. void gecko_profiler_json_writer_int_property( mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName, diff --git a/tools/profiler/rust-api/build.rs b/tools/profiler/rust-api/build.rs index 5d7a9b99d82e..053a8e434484 100644 --- a/tools/profiler/rust-api/build.rs +++ b/tools/profiler/rust-api/build.rs @@ -90,6 +90,13 @@ fn generate_bindings() { .whitelist_var("mozilla::profiler::detail::RacyFeatures::sActiveAndFeatures") .whitelist_type("mozilla::profiler::detail::RacyFeatures") .rustified_enum("mozilla::StackCaptureOptions") + .rustified_enum("mozilla::MarkerSchema_Location") + .rustified_enum("mozilla::MarkerSchema_Format") + .rustified_enum("mozilla::MarkerSchema_Searchable") + // Converting std::string to an opaque type makes some platforms build + // successfully. Otherwise, it fails to build because MarkerSchema has + // some std::strings as its fields. + .opaque_type("std::string") .raw_line("pub use self::root::*;") // Tell cargo to invalidate the built crate whenever any of the // included header files changed. diff --git a/tools/profiler/rust-api/src/marker/mod.rs b/tools/profiler/rust-api/src/marker/mod.rs index 2c6d5b004d28..3e0b323ba77f 100644 --- a/tools/profiler/rust-api/src/marker/mod.rs +++ b/tools/profiler/rust-api/src/marker/mod.rs @@ -67,6 +67,7 @@ //! TODO: Explain the marker API once we have them in the following patches. pub mod options; +pub mod schema; use crate::gecko_bindings::{bindings, profiling_categories::ProfilingCategoryPair}; use crate::marker::options::MarkerOptions; diff --git a/tools/profiler/rust-api/src/marker/schema.rs b/tools/profiler/rust-api/src/marker/schema.rs new file mode 100644 index 000000000000..9368582f1113 --- /dev/null +++ b/tools/profiler/rust-api/src/marker/schema.rs @@ -0,0 +1,233 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! [`MarkerSchema`] and other enums that will be used by `MarkerSchema`. + +use crate::gecko_bindings::{bindings, structs::mozilla}; +use std::mem::MaybeUninit; +use std::ops::DerefMut; +use std::os::raw::c_char; +use std::pin::Pin; + +/// Marker locations to be displayed in the profiler front-end. +pub type Location = mozilla::MarkerSchema_Location; + +/// Formats of marker properties for profiler front-end. +pub type Format = mozilla::MarkerSchema_Format; + +/// Whether it's searchable or not in the profiler front-end. +pub type Searchable = mozilla::MarkerSchema_Searchable; + +/// This object collects all the information necessary to stream the JSON schema +/// that informs the front-end how to display a type of markers. +/// It will be created and populated in `marker_type_display()` functions in each +/// marker type definition, see add/set functions. +/// +/// It's a RAII object that constructs and destroys a C++ MarkerSchema object +/// pointed to a specified reference. +pub struct MarkerSchema { + pub(crate) pin: Pin>>, +} + +impl MarkerSchema { + // Initialize a marker schema with the given `Location`s. + pub fn new(locations: &[Location]) -> Self { + let mut marker_schema = Box::pin(std::mem::MaybeUninit::::uninit()); + + unsafe { + bindings::gecko_profiler_construct_marker_schema( + marker_schema.deref_mut().as_mut_ptr(), + locations.as_ptr(), + locations.len(), + ); + } + MarkerSchema { pin: marker_schema } + } + + /// Marker schema for types that have special frontend handling. + /// Nothing else should be set in this case. + pub fn new_with_special_frontend_location() -> Self { + let mut marker_schema = Box::pin(std::mem::MaybeUninit::::uninit()); + unsafe { + bindings::gecko_profiler_construct_marker_schema_with_special_front_end_location( + marker_schema.deref_mut().as_mut_ptr(), + ); + } + MarkerSchema { pin: marker_schema } + } + + /// Optional label in the marker chart. + /// If not provided, the marker "name" will be used. The given string + /// can contain element keys in braces to include data elements streamed by + /// `stream_json_marker_data()`. E.g.: "This is {marker.data.text}" + pub fn set_chart_label(&mut self, label: &str) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_set_chart_label( + self.pin.deref_mut().as_mut_ptr(), + label.as_ptr() as *const c_char, + label.len(), + ); + } + self + } + + /// Optional label in the marker chart tooltip. + /// If not provided, the marker "name" will be used. The given string + /// can contain element keys in braces to include data elements streamed by + /// `stream_json_marker_data()`. E.g.: "This is {marker.data.text}" + pub fn set_tooltip_label(&mut self, label: &str) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_set_tooltip_label( + self.pin.deref_mut().as_mut_ptr(), + label.as_ptr() as *const c_char, + label.len(), + ); + } + self + } + + /// Optional label in the marker table. + /// If not provided, the marker "name" will be used. The given string + /// can contain element keys in braces to include data elements streamed by + /// `stream_json_marker_data()`. E.g.: "This is {marker.data.text}" + pub fn set_table_label(&mut self, label: &str) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_set_table_label( + self.pin.deref_mut().as_mut_ptr(), + label.as_ptr() as *const c_char, + label.len(), + ); + } + self + } + + /// Set all marker chart / marker tooltip / marker table labels with the same text. + /// Same as the individual methods, the given string can contain element keys + /// in braces to include data elements streamed by `stream_json_marker_data()`. + /// E.g.: "This is {marker.data.text}" + pub fn set_all_labels(&mut self, label: &str) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_set_all_labels( + self.pin.deref_mut().as_mut_ptr(), + label.as_ptr() as *const c_char, + label.len(), + ); + } + 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. + /// - `key`: Element property name as streamed by `stream_json_marker_data()`. + /// - `format`: How to format the data element value, see `Format` above. + pub fn add_key_format(&mut self, key: &str, format: Format) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_add_key_format( + self.pin.deref_mut().as_mut_ptr(), + key.as_ptr() as *const c_char, + key.len(), + format, + ); + } + self + } + + /// Add a key / label / format row for the marker data element. + /// - `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. + pub fn add_key_label_format(&mut self, key: &str, label: &str, format: Format) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_add_key_label_format( + self.pin.deref_mut().as_mut_ptr(), + key.as_ptr() as *const c_char, + key.len(), + label.as_ptr() as *const c_char, + label.len(), + format, + ); + } + self + } + + /// Add a key / format / searchable row for the marker data element. + /// - `key`: Element property name as streamed by `stream_json_marker_data()`. + /// - `format`: How to format the data element value, see `Format` above. + pub fn add_key_format_searchable( + &mut self, + key: &str, + format: Format, + searchable: Searchable, + ) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_add_key_format_searchable( + self.pin.deref_mut().as_mut_ptr(), + key.as_ptr() as *const c_char, + key.len(), + format, + searchable, + ); + } + self + } + + /// Add a key / label / format / searchable row for the marker data element. + /// - `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. + pub fn add_key_label_format_searchable( + &mut self, + key: &str, + label: &str, + format: Format, + searchable: Searchable, + ) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_add_key_label_format_searchable( + self.pin.deref_mut().as_mut_ptr(), + key.as_ptr() as *const c_char, + key.len(), + label.as_ptr() as *const c_char, + label.len(), + format, + searchable, + ); + } + self + } + + /// Add a key / value static row. + /// - `key`: Element property name as streamed by `stream_json_marker_data()`. + /// - `value`: Static value to display. + pub fn add_static_label_value(&mut self, label: &str, value: &str) -> &mut Self { + unsafe { + bindings::gecko_profiler_marker_schema_add_static_label_value( + self.pin.deref_mut().as_mut_ptr(), + label.as_ptr() as *const c_char, + label.len(), + value.as_ptr() as *const c_char, + value.len(), + ); + } + self + } +} + +impl Drop for MarkerSchema { + fn drop(&mut self) { + unsafe { + bindings::gecko_profiler_destruct_marker_schema(self.pin.deref_mut().as_mut_ptr()); + } + } +}