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