blob: 2b108d258ee55ec3951d8c2d10909bc4e39a0463 [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 {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));
}
}