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