blob: 93d493e9d4d09cc7db114fd5380f5048f4da9cf0 [file] [log] [blame]
// Copyright (C) 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import m from 'mithril';
import {duration, time} from '../base/time';
import {Size2D, VerticalBounds} from '../base/geom';
import {TimeScale} from '../base/time_scale';
import {HighPrecisionTimeSpan} from '../base/high_precision_time_span';
import {ColorScheme} from './color_scheme';
import {TrackEventDetailsPanel} from './details_panel';
import {TrackEventDetails, TrackEventSelection} from './selection';
import {Ds} from '../trace_processor/dataset';
export interface TrackManager {
/**
* Register a new track against a unique key known as a URI. The track is not
* shown by default and callers need to either manually add it to a
* Workspace or use registerTrackAndShowOnTraceLoad() below.
*/
registerTrack(trackDesc: TrackDescriptor): void;
findTrack(
predicate: (desc: TrackDescriptor) => boolean | undefined,
): TrackDescriptor | undefined;
getAllTracks(): TrackDescriptor[];
getTrack(uri: string): TrackDescriptor | undefined;
}
export interface TrackContext {
// This track's URI, used for making selections et al.
readonly trackUri: string;
}
/**
* Contextual information about the track passed to track lifecycle hooks &
* render hooks with additional information about the timeline/canvas.
*/
export interface TrackRenderContext extends TrackContext {
/**
* The time span of the visible window.
*/
readonly visibleWindow: HighPrecisionTimeSpan;
/**
* The dimensions of the track on the canvas in pixels.
*/
readonly size: Size2D;
/**
* Suggested data resolution.
*
* This number is the number of time units that corresponds to 1 pixel on the
* screen, rounded down to the nearest power of 2. The minimum value is 1.
*
* It's up to the track whether it would like to use this resolution or
* calculate their own based on the timespan and the track dimensions.
*/
readonly resolution: duration;
/**
* Canvas context used for rendering.
*/
readonly ctx: CanvasRenderingContext2D;
/**
* A time scale used for translating between pixels and time.
*/
readonly timescale: TimeScale;
}
// A definition of a track, including a renderer implementation and metadata.
export interface TrackDescriptor {
// A unique identifier for this track.
readonly uri: string;
// A factory function returning a new track instance.
readonly track: Track;
// Human readable title. Always displayed.
readonly title: string;
// Human readable subtitle. Sometimes displayed if there is room.
readonly subtitle?: string;
// Optional: A list of tags used for sorting, grouping and "chips".
readonly tags?: TrackTags;
readonly chips?: ReadonlyArray<string>;
readonly pluginId?: string;
}
/**
* Contextual information passed to mouse events.
*/
export interface TrackMouseEvent {
/**
* X coordinate of the mouse event w.r.t. the top-left of the track.
*/
readonly x: number;
/**
* Y coordinate of the mouse event w.r.t the top-left of the track.
*/
readonly y: number;
/**
* A time scale used for translating between pixels and time.
*/
readonly timescale: TimeScale;
}
export interface Track {
/**
* Optional lifecycle hook called on the first render cycle. Should be used to
* create any required resources.
*
* These lifecycle hooks are asynchronous, but they are run synchronously,
* meaning that perfetto will wait for each one to complete before calling the
* next one, so the user doesn't have to serialize these calls manually.
*
* Exactly when this hook is called is left purposely undefined. The only
* guarantee is that it will be called exactly once before the first call to
* onUpdate().
*
* Note: On the first render cycle, both onCreate and onUpdate are called one
* after another.
*/
onCreate?(ctx: TrackContext): Promise<void>;
/**
* Optional lifecycle hook called on every render cycle.
*
* The track should inspect things like the visible window, track size, and
* resolution to work out whether any data needs to be reloaded based on these
* properties and perform a reload.
*/
onUpdate?(ctx: TrackRenderContext): Promise<void>;
/**
* Optional lifecycle hook called when the track is no longer visible. Should
* be used to clear up any resources.
*/
onDestroy?(): Promise<void>;
/**
* Required method used to render the track's content to the canvas, called
* synchronously on every render cycle.
*/
render(ctx: TrackRenderContext): void;
onFullRedraw?(): void;
/**
* Return the vertical bounds (top & bottom) of a slice were it to be rendered
* at a specific depth, given the slice height and padding/spacing that this
* track uses.
*/
getSliceVerticalBounds?(depth: number): VerticalBounds | undefined;
getHeight(): number;
getTrackShellButtons?(): m.Children;
onMouseMove?(event: TrackMouseEvent): void;
onMouseClick?(event: TrackMouseEvent): boolean;
onMouseOut?(): void;
/**
* Optional: Returns a dataset that represents the events displayed on this
* track.
*/
getDataset?(): Ds.Dataset | undefined;
/**
* Optional: Get details of a track event given by eventId on this track.
*/
getSelectionDetails?(eventId: number): Promise<TrackEventDetails | undefined>;
// Optional: A factory that returns a details panel object for a given track
// event selection. This is called each time the selection is changed (and the
// selection is relevant to this track).
detailsPanel?(sel: TrackEventSelection): TrackEventDetailsPanel;
}
// An set of key/value pairs describing a given track. These are used for
// selecting tracks to pin/unpin, diplsaying "chips" in the track shell, and
// (in future) the sorting and grouping of tracks.
// We define a handful of well known fields, and the rest are arbitrary key-
// value pairs.
export type TrackTags = Partial<WellKnownTrackTags> & {
// There may be arbitrary other key/value pairs.
[key: string]:
| undefined
| string
| number
| boolean
| ReadonlyArray<string>
| ReadonlyArray<number>;
};
interface WellKnownTrackTags {
// The track "kind", used by various subsystems e.g. aggregation controllers.
// This is where "XXX_TRACK_KIND" values should be placed.
// TODO(stevegolton): This will be deprecated once we handle group selections
// in a more generic way - i.e. EventSet.
kind: string;
// Optional: list of track IDs represented by this trace.
// This list is used for participation in track indexing by track ID.
// This index is used by various subsystems to find links between tracks based
// on the track IDs used by trace processor.
trackIds: ReadonlyArray<number>;
// Optional: The CPU number associated with this track.
cpu: number;
// Optional: The UTID associated with this track.
utid: number;
// Optional: The UPID associated with this track.
upid: number;
// Used for sorting and grouping
scope: string;
// Group name, used as a hint to ask track decider to put this in a group
groupName: string;
}
export interface Slice {
// These properties are updated only once per query result when the Slice
// object is created and don't change afterwards.
readonly id: number;
readonly startNs: time;
readonly endNs: time;
readonly durNs: duration;
readonly ts: time;
readonly dur: duration;
readonly depth: number;
readonly flags: number;
// Each slice can represent some extra numerical information by rendering a
// portion of the slice with a lighter tint.
// |fillRatio\ describes the ratio of the normal area to the tinted area
// width of the slice, normalized between 0.0 -> 1.0.
// 0.0 means the whole slice is tinted.
// 1.0 means none of the slice is tinted.
// E.g. If |fillRatio| = 0.65 the slice will be rendered like this:
// [############|*******]
// ^------------^-------^
// Normal Light
readonly fillRatio: number;
// These can be changed by the Impl.
title: string;
subTitle: string;
colorScheme: ColorScheme;
isHighlighted: boolean;
}