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}