| // Copyright (C) 2022 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 {Hotkey} from '../base/hotkeys'; |
| import {duration, Span, time} from '../base/time'; |
| import {EngineProxy} from '../common/engine'; |
| import {TrackControllerFactory} from '../controller/track_controller'; |
| import {Store} from '../frontend/store'; |
| import {PxSpan, TimeScale} from '../frontend/time_scale'; |
| import {SliceRect, TrackCreator} from '../frontend/track'; |
| import {TrackButtonAttrs} from '../frontend/track_panel'; |
| |
| export {EngineProxy} from '../common/engine'; |
| export { |
| LONG, |
| LONG_NULL, |
| NUM, |
| NUM_NULL, |
| STR, |
| STR_NULL, |
| } from '../common/query_result'; |
| export {Store} from '../frontend/store'; |
| |
| |
| // An imperative API for plugins to change the UI. |
| export interface Viewer { |
| // Control of the sidebar. |
| sidebar: { |
| // Show the sidebar. |
| show(): void; |
| // Hide the sidebar. |
| hide(): void; |
| // Returns true if the sidebar is visble. |
| isVisible(): boolean; |
| } |
| |
| // Tracks |
| tracks: { |
| pin(predicate: TrackPredicate): void; |
| unpin(predicate: TrackPredicate): void; |
| } |
| |
| // Control over the bottom details pane. |
| tabs: { |
| // Creates a new tab running the provided query. |
| openQuery(query: string, title: string): void; |
| } |
| |
| commands: {run(name: string, ...args: any[]): void;} |
| } |
| |
| export interface Command { |
| // A unique id for this command. |
| id: string; |
| // A human-friendly name for this command. |
| name: string; |
| // Callback is called when the command is invoked. |
| callback: (...args: any[]) => void; |
| // Default hotkey for this command. |
| // Note: this is just the default and may be changed by the user. |
| // Examples: |
| // - 'P' |
| // - 'Shift+P' |
| // - '!Mod+Shift+P' |
| // See hotkeys.ts for guidance on hotkey syntax. |
| defaultHotkey?: Hotkey; |
| } |
| |
| export interface MetricVisualisation { |
| // The name of the metric e.g. 'android_camera' |
| metric: string; |
| |
| // A vega or vega-lite visualisation spec. |
| // The data from the metric under path will be exposed as a |
| // datasource named "metric" in Vega(-Lite) |
| spec: string; |
| |
| // A path index into the metric. |
| // For example if the metric returns the folowing protobuf: |
| // { |
| // foo { |
| // bar { |
| // baz: { name: "a" } |
| // baz: { name: "b" } |
| // baz: { name: "c" } |
| // } |
| // } |
| // } |
| // That becomes the following json: |
| // { "foo": { "bar": { "baz": [ |
| // {"name": "a"}, |
| // {"name": "b"}, |
| // {"name": "c"}, |
| // ]}}} |
| // And given path = ["foo", "bar", "baz"] |
| // We extract: |
| // [ {"name": "a"}, {"name": "b"}, {"name": "c"} ] |
| // And pass that to the vega(-lite) visualisation. |
| path: string[]; |
| } |
| |
| export interface MetricVisualisation { |
| // The name of the metric e.g. 'android_camera' |
| metric: string; |
| |
| // A vega or vega-lite visualisation spec. |
| // The data from the metric under path will be exposed as a |
| // datasource named "metric" in Vega(-Lite) |
| spec: string; |
| |
| // A path index into the metric. |
| // For example if the metric returns the folowing protobuf: |
| // { |
| // foo { |
| // bar { |
| // baz: { name: "a" } |
| // baz: { name: "b" } |
| // baz: { name: "c" } |
| // } |
| // } |
| // } |
| // That becomes the following json: |
| // { "foo": { "bar": { "baz": [ |
| // {"name": "a"}, |
| // {"name": "b"}, |
| // {"name": "c"}, |
| // ]}}} |
| // And given path = ["foo", "bar", "baz"] |
| // We extract: |
| // [ {"name": "a"}, {"name": "b"}, {"name": "c"} ] |
| // And pass that to the vega(-lite) visualisation. |
| path: string[]; |
| } |
| |
| // This interface defines a context for a plugin, which is an object passed to |
| // most hooks within the plugin. It should be used to interact with Perfetto. |
| export interface PluginContext { |
| readonly viewer: Viewer; |
| |
| // DEPRECATED. In prior versions of the UI tracks were split into a |
| // 'TrackController' and a 'Track'. In more recent versions of the UI |
| // the functionality of |TrackController| has been merged into Track so |
| // |TrackController|s are not necessary in new code. |
| registerTrackController(track: TrackControllerFactory): void; |
| |
| // Register a track factory. The core UI invokes |TrackCreator| to |
| // construct tracks discovered by invoking |TrackProvider|s. |
| // The split between 'construction' and 'discovery' allows |
| // plugins to reuse common tracks for new data. For example: the |
| // dev.perfetto.AndroidGpu plugin could register a TrackProvider |
| // which returns GPU counter tracks. The counter track factory itself |
| // could be registered in dev.perfetto.CounterTrack - a whole |
| // different plugin. |
| registerTrack(track: TrackCreator): void; |
| |
| // Add a command. |
| addCommand(command: Command): void; |
| } |
| |
| export interface TrackContext { |
| // A unique ID for the instance of this track. |
| trackInstanceId: string; |
| } |
| |
| export interface TrackContext { |
| // A unique ID for the instance of this track. |
| trackInstanceId: string; |
| } |
| |
| // TODO(stevegolton): Rename `Track` to `BaseTrack` (or similar) and rename this |
| // interface to `Track`. |
| export interface TrackLike { |
| onCreate(): void; |
| render(ctx: CanvasRenderingContext2D): void; |
| onFullRedraw(): void; |
| getSliceRect( |
| visibleTimeScale: TimeScale, visibleWindow: Span<time, duration>, |
| windowSpan: PxSpan, tStart: time, tEnd: time, depth: number): SliceRect |
| |undefined; |
| getHeight(): number; |
| getTrackShellButtons(): Array<m.Vnode<TrackButtonAttrs>>; |
| getContextMenu(): m.Vnode<any>|null; |
| onMouseMove(position: {x: number, y: number}): void; |
| onMouseClick(position: {x: number, y: number}): boolean; |
| onMouseOut(): void; |
| onDestroy(): void; |
| } |
| |
| export interface PluginTrackInfo { |
| // A unique identifier for the track. This must be unique within all tracks. |
| uri: string; |
| |
| // A human friendly name for this track. Used when displaying the list of |
| // tracks to the user. E.g. when adding a new track to the workspace. |
| displayName: string; |
| |
| // A factory function returning the track object. |
| trackFactory: (ctx: TrackContext) => TrackLike; |
| |
| // A list of tags used for sorting and grouping. |
| tags?: TrackTags; |
| } |
| |
| // Similar to PluginContext but with additional properties to operate on the |
| // currently loaded trace. Passed to trace-relevant hooks instead of |
| // PluginContext. |
| export interface TracePluginContext<T = undefined> extends PluginContext { |
| readonly engine: EngineProxy; |
| readonly store: Store<T>; |
| |
| // Add a new track from this plugin. The track is just made available here, |
| // it's not automatically shown until it's added to a workspace. |
| addTrack(trackDetails: PluginTrackInfo): void; |
| } |
| |
| export interface BasePlugin<State> { |
| // Lifecycle methods. |
| onActivate(ctx: PluginContext): void; |
| onTraceLoad?(ctx: TracePluginContext<State>): Promise<void>; |
| onTraceUnload?(ctx: TracePluginContext<State>): Promise<void>; |
| onDeactivate?(ctx: PluginContext): void; |
| |
| // Extension points. |
| metricVisualisations?(ctx: PluginContext): MetricVisualisation[]; |
| findPotentialTracks?(ctx: TracePluginContext<State>): Promise<TrackInfo[]>; |
| } |
| |
| export interface StatefulPlugin<State> extends BasePlugin<State> { |
| // Function to migrate the persistent state. |
| migrate(initialState: unknown): State; |
| } |
| |
| // Generic interface all plugins must implement. |
| // If a state type is passed, the plugin must implement migrate(). Otherwise if |
| // the state type is omitted, migrate need not be defined. |
| export type Plugin<State = undefined> = |
| State extends undefined ? BasePlugin<State>: StatefulPlugin<State>; |
| |
| // This interface defines what a plugin factory should look like. |
| // This can be defined in the plugin class definition by defining a constructor |
| // and the relevant static methods: |
| // E.g. |
| // class MyPlugin implements TracePlugin<MyState> { |
| // migrate(initialState: unknown): MyState {...} |
| // constructor(store: Store<MyState>, engine: EngineProxy) {...} |
| // ... methods from the TracePlugin interface go here ... |
| // } |
| // ... which can then be passed around by class i.e. MyPlugin |
| export interface PluginClass<T> { |
| // Instantiate the plugin. |
| new(): Plugin<T>; |
| } |
| |
| export interface TrackInfo { |
| // The id of this 'type' of track. This id is used to select the |
| // correct |TrackCreator| to construct the track. |
| trackKind: string; |
| |
| // A human readable name for this specific track. It will normally be |
| // displayed on the left-hand-side of the track. |
| name: string; |
| |
| // An opaque config for the track. |
| config: {}; |
| } |
| |
| // A predicate for selecting a groups of tracks. |
| export type TrackPredicate = (info: TrackTags) => boolean; |
| |
| interface WellKnownTrackTags { |
| // A human readable name for this specific track. |
| name: string; |
| |
| // This is where "XXX_TRACK_KIND" values should be placed. |
| kind: string; |
| |
| // The CPU number associated with this track. |
| cpu: number; |
| } |
| |
| // An set of key/value pairs describing a given track. These are used for |
| // selecting tracks to pin/unpin and (in future) the sorting and grouping of |
| // tracks. |
| // These are also (ab)used for communicating information about tracks for the |
| // purposes of locating tracks by their properties e.g. aggregation & search. |
| // 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]: string|number|undefined; |
| } |
| |
| // Plugins can be passed as class refs, factory functions, or concrete plugin |
| // implementations. |
| export type PluginFactory<T> = PluginClass<T>|Plugin<T>|(() => Plugin<T>); |
| |
| export interface PluginInfo<T = undefined> { |
| // A unique string for your plugin. To ensure the name is unique you |
| // may wish to use a URL with reversed components in the manner of |
| // Java package names. |
| pluginId: string; |
| |
| // The plugin factory used to instantiate the plugin object, or if this is |
| // an actual plugin implementation, it's just used as-is. |
| plugin: PluginFactory<T>; |
| } |