xref: /aosp_15_r20/external/perfetto/ui/src/public/track.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2024 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import m from 'mithril';
16import {duration, time} from '../base/time';
17import {Size2D, VerticalBounds} from '../base/geom';
18import {TimeScale} from '../base/time_scale';
19import {HighPrecisionTimeSpan} from '../base/high_precision_time_span';
20import {ColorScheme} from './color_scheme';
21import {TrackEventDetailsPanel} from './details_panel';
22import {TrackEventDetails, TrackEventSelection} from './selection';
23import {Dataset} from '../trace_processor/dataset';
24
25export interface TrackManager {
26  /**
27   * Register a new track against a unique key known as a URI. The track is not
28   * shown by default and callers need to either manually add it to a
29   * Workspace or use registerTrackAndShowOnTraceLoad() below.
30   */
31  registerTrack(trackDesc: TrackDescriptor): void;
32
33  findTrack(
34    predicate: (desc: TrackDescriptor) => boolean | undefined,
35  ): TrackDescriptor | undefined;
36
37  getAllTracks(): TrackDescriptor[];
38
39  getTrack(uri: string): TrackDescriptor | undefined;
40}
41
42export interface TrackContext {
43  // This track's URI, used for making selections et al.
44  readonly trackUri: string;
45}
46
47/**
48 * Contextual information about the track passed to track lifecycle hooks &
49 * render hooks with additional information about the timeline/canvas.
50 */
51export interface TrackRenderContext extends TrackContext {
52  /**
53   * The time span of the visible window.
54   */
55  readonly visibleWindow: HighPrecisionTimeSpan;
56
57  /**
58   * The dimensions of the track on the canvas in pixels.
59   */
60  readonly size: Size2D;
61
62  /**
63   * Suggested data resolution.
64   *
65   * This number is the number of time units that corresponds to 1 pixel on the
66   * screen, rounded down to the nearest power of 2. The minimum value is 1.
67   *
68   * It's up to the track whether it would like to use this resolution or
69   * calculate their own based on the timespan and the track dimensions.
70   */
71  readonly resolution: duration;
72
73  /**
74   * Canvas context used for rendering.
75   */
76  readonly ctx: CanvasRenderingContext2D;
77
78  /**
79   * A time scale used for translating between pixels and time.
80   */
81  readonly timescale: TimeScale;
82}
83
84// A definition of a track, including a renderer implementation and metadata.
85export interface TrackDescriptor {
86  // A unique identifier for this track.
87  readonly uri: string;
88
89  // A factory function returning a new track instance.
90  readonly track: Track;
91
92  // Human readable title. Always displayed.
93  readonly title: string;
94
95  // Human readable subtitle. Sometimes displayed if there is room.
96  readonly subtitle?: string;
97
98  // Optional: A list of tags used for sorting, grouping and "chips".
99  readonly tags?: TrackTags;
100
101  readonly chips?: ReadonlyArray<string>;
102
103  readonly pluginId?: string;
104}
105
106/**
107 * Contextual information passed to mouse events.
108 */
109export interface TrackMouseEvent {
110  /**
111   * X coordinate of the mouse event w.r.t. the top-left of the track.
112   */
113  readonly x: number;
114
115  /**
116   * Y coordinate of the mouse event w.r.t the top-left of the track.
117   */
118  readonly y: number;
119
120  /**
121   * A time scale used for translating between pixels and time.
122   */
123  readonly timescale: TimeScale;
124}
125
126export interface Track {
127  /**
128   * Optional lifecycle hook called on the first render cycle. Should be used to
129   * create any required resources.
130   *
131   * These lifecycle hooks are asynchronous, but they are run synchronously,
132   * meaning that perfetto will wait for each one to complete before calling the
133   * next one, so the user doesn't have to serialize these calls manually.
134   *
135   * Exactly when this hook is called is left purposely undefined. The only
136   * guarantee is that it will be called exactly once before the first call to
137   * onUpdate().
138   *
139   * Note: On the first render cycle, both onCreate and onUpdate are called one
140   * after another.
141   */
142  onCreate?(ctx: TrackContext): Promise<void>;
143
144  /**
145   * Optional lifecycle hook called on every render cycle.
146   *
147   * The track should inspect things like the visible window, track size, and
148   * resolution to work out whether any data needs to be reloaded based on these
149   * properties and perform a reload.
150   */
151  onUpdate?(ctx: TrackRenderContext): Promise<void>;
152
153  /**
154   * Optional lifecycle hook called when the track is no longer visible. Should
155   * be used to clear up any resources.
156   */
157  onDestroy?(): Promise<void>;
158
159  /**
160   * Required method used to render the track's content to the canvas, called
161   * synchronously on every render cycle.
162   */
163  render(ctx: TrackRenderContext): void;
164  onFullRedraw?(): void;
165
166  /**
167   * Return the vertical bounds (top & bottom) of a slice were it to be rendered
168   * at a specific depth, given the slice height and padding/spacing that this
169   * track uses.
170   */
171  getSliceVerticalBounds?(depth: number): VerticalBounds | undefined;
172  getHeight(): number;
173  getTrackShellButtons?(): m.Children;
174  onMouseMove?(event: TrackMouseEvent): void;
175  onMouseClick?(event: TrackMouseEvent): boolean;
176  onMouseOut?(): void;
177
178  /**
179   * Optional: Returns a dataset that represents the events displayed on this
180   * track.
181   */
182  getDataset?(): Dataset | undefined;
183
184  /**
185   * Optional: Get details of a track event given by eventId on this track.
186   */
187  getSelectionDetails?(eventId: number): Promise<TrackEventDetails | undefined>;
188
189  // Optional: A factory that returns a details panel object for a given track
190  // event selection. This is called each time the selection is changed (and the
191  // selection is relevant to this track).
192  detailsPanel?(sel: TrackEventSelection): TrackEventDetailsPanel;
193}
194
195// An set of key/value pairs describing a given track. These are used for
196// selecting tracks to pin/unpin, diplsaying "chips" in the track shell, and
197// (in future) the sorting and grouping of tracks.
198// We define a handful of well known fields, and the rest are arbitrary key-
199// value pairs.
200export type TrackTags = Partial<WellKnownTrackTags> & {
201  // There may be arbitrary other key/value pairs.
202  [key: string]:
203    | undefined
204    | string
205    | number
206    | boolean
207    | ReadonlyArray<string>
208    | ReadonlyArray<number>;
209};
210
211interface WellKnownTrackTags {
212  // The track "kind", used by various subsystems e.g. aggregation controllers.
213  // This is where "XXX_TRACK_KIND" values should be placed.
214  // TODO(stevegolton): This will be deprecated once we handle group selections
215  // in a more generic way - i.e. EventSet.
216  kind: string;
217
218  // Optional: list of track IDs represented by this trace.
219  // This list is used for participation in track indexing by track ID.
220  // This index is used by various subsystems to find links between tracks based
221  // on the track IDs used by trace processor.
222  trackIds: ReadonlyArray<number>;
223
224  // Optional: The CPU number associated with this track.
225  cpu: number;
226
227  // Optional: The UTID associated with this track.
228  utid: number;
229
230  // Optional: The UPID associated with this track.
231  upid: number;
232
233  // Used for sorting and grouping
234  scope: string;
235
236  // Group name, used as a hint to ask track decider to put this in a group
237  groupName: string;
238}
239
240export interface Slice {
241  // These properties are updated only once per query result when the Slice
242  // object is created and don't change afterwards.
243  readonly id: number;
244  readonly startNs: time;
245  readonly endNs: time;
246  readonly durNs: duration;
247  readonly ts: time;
248  readonly dur: duration;
249  readonly depth: number;
250  readonly flags: number;
251
252  // Each slice can represent some extra numerical information by rendering a
253  // portion of the slice with a lighter tint.
254  // |fillRatio\ describes the ratio of the normal area to the tinted area
255  // width of the slice, normalized between 0.0 -> 1.0.
256  // 0.0 means the whole slice is tinted.
257  // 1.0 means none of the slice is tinted.
258  // E.g. If |fillRatio| = 0.65 the slice will be rendered like this:
259  // [############|*******]
260  // ^------------^-------^
261  //     Normal     Light
262  readonly fillRatio: number;
263
264  // These can be changed by the Impl.
265  title: string;
266  subTitle: string;
267  colorScheme: ColorScheme;
268  isHighlighted: boolean;
269}
270