fxprof_processed_profile/
markers.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use serde::Serialize;
6use serde_json::Value;
7
8use super::timestamp::Timestamp;
9
10/// Specifies timestamps for a marker.
11#[derive(Debug, Clone)]
12pub enum MarkerTiming {
13    /// Instant markers describe a single point in time.
14    Instant(Timestamp),
15    /// Interval markers describe a time interval with a start and end timestamp.
16    Interval(Timestamp, Timestamp),
17    /// A marker for just the start of an actual marker. Can be paired with an
18    /// `IntervalEnd` marker of the same name; if no end marker is supplied, this
19    /// creates a marker that extends to the end of the profile.
20    ///
21    /// This can be used for long-running markers for pieces of activity that may
22    /// not have completed by the time the profile is captured.
23    IntervalStart(Timestamp),
24    /// A marker for just the end of an actual marker. Can be paired with an
25    /// `IntervalStart` marker of the same name; if no start marker is supplied,
26    /// this creates a marker which started before the beginning of the profile.
27    ///
28    /// This can be used to mark pieces of activity which started before profiling
29    /// began.
30    IntervalEnd(Timestamp),
31}
32
33/// The trait that all markers implement.
34///
35///
36/// ```
37/// use fxprof_processed_profile::{ProfilerMarker, MarkerLocation, MarkerFieldFormat, MarkerSchema, MarkerDynamicField, MarkerSchemaField};
38/// use serde_json::json;
39///
40/// /// An example marker type with some text content.
41/// #[derive(Debug, Clone)]
42/// pub struct TextMarker(pub String);
43///
44/// impl ProfilerMarker for TextMarker {
45///     const MARKER_TYPE_NAME: &'static str = "Text";
46///
47///     fn json_marker_data(&self) -> serde_json::Value {
48///         json!({
49///             "type": Self::MARKER_TYPE_NAME,
50///             "name": self.0
51///         })
52///     }
53///
54///     fn schema() -> MarkerSchema {
55///         MarkerSchema {
56///             type_name: Self::MARKER_TYPE_NAME,
57///             locations: vec![MarkerLocation::MarkerChart, MarkerLocation::MarkerTable],
58///             chart_label: Some("{marker.data.name}"),
59///             tooltip_label: None,
60///             table_label: Some("{marker.name} - {marker.data.name}"),
61///             fields: vec![MarkerSchemaField::Dynamic(MarkerDynamicField {
62///                 key: "name",
63///                 label: "Details",
64///                 format: MarkerFieldFormat::String,
65///                 searchable: true,
66///             })],
67///         }
68///     }
69/// }
70/// ```
71pub trait ProfilerMarker {
72    /// The name of the marker type.
73    const MARKER_TYPE_NAME: &'static str;
74
75    /// A static method that returns a `MarkerSchema`, which contains all the
76    /// information needed to stream the display schema associated with a
77    /// marker type.
78    fn schema() -> MarkerSchema;
79
80    /// A method that streams the marker payload data as a serde_json object.
81    fn json_marker_data(&self) -> Value;
82}
83
84/// Describes a marker type.
85#[derive(Debug, Clone, Serialize)]
86#[serde(rename_all = "camelCase")]
87pub struct MarkerSchema {
88    /// The name of this marker type.
89    #[serde(rename = "name")]
90    pub type_name: &'static str,
91
92    /// List of marker display locations. Empty for SpecialFrontendLocation.
93    #[serde(rename = "display")]
94    pub locations: Vec<MarkerLocation>,
95
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub chart_label: Option<&'static str>,
98
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub tooltip_label: Option<&'static str>,
101
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub table_label: Option<&'static str>,
104
105    /// The marker fields. These can be specified on each marker.
106    #[serde(rename = "data")]
107    pub fields: Vec<MarkerSchemaField>,
108}
109
110/// The location of markers with this type.
111///
112/// Markers can be shown in different parts of the Firefox Profiler UI.
113///
114/// Multiple [`MarkerLocation`]s can be specified for a single marker type.
115#[derive(Debug, Clone, Serialize)]
116#[serde(rename_all = "kebab-case")]
117pub enum MarkerLocation {
118    MarkerChart,
119    MarkerTable,
120    /// This adds markers to the main marker timeline in the header.
121    TimelineOverview,
122    /// In the timeline, this is a section that breaks out markers that are
123    /// related to memory. When memory counters are enabled, this is its own
124    /// track, otherwise it is displayed with the main thread.
125    TimelineMemory,
126    /// This adds markers to the IPC timeline area in the header.
127    TimelineIPC,
128    /// This adds markers to the FileIO timeline area in the header.
129    #[serde(rename = "timeline-fileio")]
130    TimelineFileIO,
131    /// TODO - This is not supported yet.
132    StackChart,
133}
134
135/// The description of a marker field in the marker type's schema.
136#[derive(Debug, Clone, Serialize)]
137#[serde(untagged)]
138pub enum MarkerSchemaField {
139    /// Static fields have the same value on all markers. This is used for
140    /// a "Description" field in the tooltip, for example.
141    Static(MarkerStaticField),
142
143    /// Dynamic fields have a per-marker value. The ProfilerMarker implementation
144    /// on the marker type needs to serialize a field on the data JSON object with
145    /// the matching key.
146    Dynamic(MarkerDynamicField),
147}
148
149/// The field description of a marker field which has the same key and value on all markers with this schema.
150#[derive(Debug, Clone, Serialize)]
151pub struct MarkerStaticField {
152    pub label: &'static str,
153    pub value: &'static str,
154}
155
156/// The field description of a marker field which can have a different value for each marker.
157#[derive(Debug, Clone, Serialize)]
158pub struct MarkerDynamicField {
159    /// The field key.
160    pub key: &'static str,
161
162    /// The user-visible label of this field.
163    #[serde(skip_serializing_if = "str::is_empty")]
164    pub label: &'static str,
165
166    /// The format of this field.
167    pub format: MarkerFieldFormat,
168
169    /// Whether this field's value should be matched against search terms.
170    pub searchable: bool,
171}
172
173/// The field format of a marker field.
174#[derive(Debug, Clone, Serialize)]
175#[serde(rename_all = "kebab-case")]
176pub enum MarkerFieldFormat {
177    // ----------------------------------------------------
178    // String types.
179    /// A URL, supports PII sanitization
180    Url,
181
182    /// A file path, supports PII sanitization.
183    FilePath,
184
185    /// A plain String, never sanitized for PII.
186    /// Important: Do not put URL or file path information here, as it will not
187    /// be sanitized during profile upload. Please be careful with including
188    /// other types of PII here as well.
189    String,
190
191    // ----------------------------------------------------
192    // Numeric types
193    /// For time data that represents a duration of time.
194    /// e.g. "Label: 5s, 5ms, 5μs"
195    Duration,
196
197    /// Data that happened at a specific time, relative to the start of the
198    /// profile. e.g. "Label: 15.5s, 20.5ms, 30.5μs"
199    Time,
200
201    /// The following are alternatives to display a time only in a specific unit
202    /// of time.
203    Seconds, // "Label: 5s"
204    Milliseconds, // "Label: 5ms"
205    Microseconds, // "Label: 5μs"
206    Nanoseconds,  // "Label: 5ns"
207
208    /// e.g. "Label: 5.55mb, 5 bytes, 312.5kb"
209    Bytes,
210
211    /// This should be a value between 0 and 1.
212    /// "Label: 50%"
213    Percentage,
214
215    // The integer should be used for generic representations of numbers.
216    // Do not use it for time information.
217    // "Label: 52, 5,323, 1,234,567"
218    Integer,
219
220    // The decimal should be used for generic representations of numbers.
221    // Do not use it for time information.
222    // "Label: 52.23, 0.0054, 123,456.78"
223    Decimal,
224}