| // 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 {globals} from '../../frontend/globals'; |
| import { |
| SimpleSliceTrack, |
| SimpleSliceTrackConfig, |
| } from '../../frontend/simple_slice_track'; |
| import {addDebugSliceTrack, PluginContextTrace} from '../../public'; |
| import {findCurrentSelection} from '../../frontend/keyboard_event_handler'; |
| import {time, Time} from '../../base/time'; |
| import {BigintMath} from '../../base/bigint_math'; |
| import {reveal} from '../../frontend/scroll_helper'; |
| |
| // Common TrackType for tracks when using registerStatic or addDebug |
| // TODO: b/349502258 - to be removed after single refactoring to single API |
| export type TrackType = 'static' | 'debug'; |
| |
| /** |
| * Adds debug tracks from SimpleSliceTrackConfig |
| * Static tracks cannot be added on command |
| * TODO: b/349502258 - To be removed later |
| * |
| * @param {PluginContextTrace} ctx Context for trace methods and properties |
| * @param {SimpleSliceTrackConfig} config Track config to add |
| * @param {string} trackName Track name to display |
| */ |
| export function addDebugTrackOnCommand( |
| ctx: PluginContextTrace, |
| config: SimpleSliceTrackConfig, |
| trackName: string, |
| ) { |
| addDebugSliceTrack( |
| ctx, |
| config.data, |
| trackName, |
| config.columns, |
| config.argColumns, |
| ); |
| } |
| |
| /** |
| * Registers and pins tracks on traceload, given params |
| * TODO: b/349502258 - Refactor to single API |
| * |
| * @param {PluginContextTrace} ctx Context for trace methods and properties |
| * @param {SimpleSliceTrackConfig} config Track config to add |
| * @param {string} trackName Track name to display |
| * @param {string} uri Unique identifier for the track |
| */ |
| export function addDebugTrackOnTraceLoad( |
| ctx: PluginContextTrace, |
| config: SimpleSliceTrackConfig, |
| trackName: string, |
| uri: string, |
| ) { |
| ctx.registerStaticTrack({ |
| uri: uri, |
| title: trackName, |
| isPinned: true, |
| trackFactory: (trackCtx) => { |
| return new SimpleSliceTrack(ctx.engine, trackCtx, config); |
| }, |
| }); |
| } |
| |
| /** |
| * Registers and pins tracks on traceload or command |
| * Every enabled plugins' onTraceload is executed when the trace is first loaded |
| * To add and pin tracks on traceload, need to use registerStaticTrack |
| * After traceload, if plugin registered command invocated, then addDebugSliceTrack |
| * TODO: b/349502258 - Refactor to single API |
| * |
| * @param {PluginContextTrace} ctx Context for trace methods and properties |
| * @param {SimpleSliceTrackConfig} config Track config to add |
| * @param {string} trackName Track name to display |
| * @param {TrackType} type Whether to registerStaticTrack or addDebugSliceTrack |
| * type 'static' expects caller to pass uri string |
| * @param {string} uri Unique track identifier expected when type is 'static' |
| */ |
| export function addAndPinSliceTrack( |
| ctx: PluginContextTrace, |
| config: SimpleSliceTrackConfig, |
| trackName: string, |
| type: TrackType, |
| uri?: string, |
| ) { |
| if (type == 'static') { |
| addDebugTrackOnTraceLoad(ctx, config, trackName, uri ?? ''); |
| } else if (type == 'debug') { |
| addDebugTrackOnCommand(ctx, config, trackName); |
| } |
| } |
| |
| /** |
| * Interface for slice identifier |
| */ |
| export interface SliceIdentifier { |
| sliceId?: number; |
| trackId?: number; |
| ts?: time; |
| dur?: bigint; |
| } |
| |
| /** |
| * Sets focus on a specific slice within the trace data. |
| * |
| * Takes and adds desired slice to current selection |
| * Retrieves the track key and scrolls to the desired slice |
| * |
| * @param {SliceIdentifier} slice slice to focus on with trackId and sliceId |
| */ |
| |
| export function focusOnSlice(slice: SliceIdentifier) { |
| if (slice.sliceId == undefined || slice.trackId == undefined) { |
| return; |
| } |
| const trackId = slice.trackId; |
| const trackKey = getTrackKey(trackId); |
| globals.setLegacySelection( |
| { |
| kind: 'SLICE', |
| id: slice.sliceId, |
| trackKey: trackKey, |
| table: 'slice', |
| }, |
| { |
| clearSearch: true, |
| pendingScrollId: slice.sliceId, |
| switchToCurrentSelectionTab: true, |
| }, |
| ); |
| findCurrentSelection; |
| } |
| |
| /** |
| * Given the trackId of the track, retrieves its trackKey |
| * |
| * @param {number} trackId track_id of the track |
| * @returns {string} trackKey given to the track with queried trackId |
| */ |
| function getTrackKey(trackId: number): string | undefined { |
| return globals.trackManager.trackKeyByTrackId.get(trackId); |
| } |
| |
| /** |
| * Sets focus on a specific time span and a track |
| * |
| * Takes a row object pans the view to that time span |
| * Retrieves the track key and scrolls to the desired track |
| * |
| * @param {SliceIdentifier} slice slice to focus on with trackId and time data |
| */ |
| |
| export async function focusOnTimeAndTrack(slice: SliceIdentifier) { |
| if ( |
| slice.trackId == undefined || |
| slice.ts == undefined || |
| slice.dur == undefined |
| ) { |
| return; |
| } |
| const trackId = slice.trackId; |
| const sliceStart = slice.ts; |
| // row.dur can be negative. Clamp to 1ns. |
| const sliceDur = BigintMath.max(slice.dur, 1n); |
| const trackKey = getTrackKey(trackId); |
| // true for whether to expand the process group the track belongs to |
| if (trackKey == undefined) { |
| return; |
| } |
| reveal(trackKey, sliceStart, Time.add(sliceStart, sliceDur), true); |
| } |
| |
| /** |
| * Function to check keep checking for object values at set intervals |
| * |
| * @param {T | undefined} getValue Function to retrieve object value |
| * @returns {T} Value returned by getValue when available |
| */ |
| export async function waitForValue<T>(getValue: () => T): Promise<T> { |
| while (true) { |
| // TODO: b/353466921 - update when waiForTraceLoad function added |
| const value = getValue(); |
| if (value !== undefined) { |
| return value; |
| } |
| await new Promise((resolve) => setTimeout(resolve, 100)); |
| } |
| } |