| // 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 {uuidv4} from '../base/uuid'; |
| import {Actions, DeferredAction} from '../common/actions'; |
| import {SCROLLING_TRACK_GROUP} from '../common/state'; |
| import {globals} from './globals'; |
| import {Engine, PrimaryTrackSortKey} from '../public'; |
| import {DebugTrackV2Config} from '../core_plugins/debug/slice_track'; |
| |
| export const ARG_PREFIX = 'arg_'; |
| export const DEBUG_SLICE_TRACK_URI = 'perfetto.DebugSlices'; |
| export const DEBUG_COUNTER_TRACK_URI = 'perfetto.DebugCounter'; |
| |
| // Names of the columns of the underlying view to be used as |
| // ts / dur / name / pivot. |
| export interface SliceColumns { |
| ts: string; |
| dur: string; |
| name: string; |
| pivot?: string; |
| } |
| |
| export interface DebugTrackV2CreateConfig { |
| pinned?: boolean; // default true |
| closeable?: boolean; // default true |
| } |
| |
| let debugTrackCount = 0; |
| |
| export interface SqlDataSource { |
| // SQL source selecting the necessary data. |
| sqlSource: string; |
| |
| // Optional: Rename columns from the query result. |
| // If omitted, original column names from the query are used instead. |
| // The caller is responsible for ensuring that the number of items in this |
| // list matches the number of columns returned by sqlSource. |
| columns?: string[]; |
| } |
| |
| // Creates actions to add a debug track. The actions must be dispatched to |
| // have an effect. Use this variant if you want to create many tracks at |
| // once or want to tweak the actions once produced. Otherwise, use |
| // addDebugSliceTrack(). |
| export async function createDebugSliceTrackActions( |
| _engine: Engine, |
| data: SqlDataSource, |
| trackName: string, |
| sliceColumns: SliceColumns, |
| argColumns: string[], |
| config?: DebugTrackV2CreateConfig, |
| ): Promise<DeferredAction<{}>[]> { |
| const debugTrackId = ++debugTrackCount; |
| const closeable = config?.closeable ?? true; |
| const trackKey = uuidv4(); |
| |
| const trackConfig: DebugTrackV2Config = { |
| data, |
| columns: sliceColumns, |
| argColumns, |
| }; |
| |
| const actions: DeferredAction<{}>[] = [ |
| Actions.addTrack({ |
| key: trackKey, |
| name: trackName.trim() || `Debug Track ${debugTrackId}`, |
| uri: DEBUG_SLICE_TRACK_URI, |
| trackSortKey: PrimaryTrackSortKey.DEBUG_TRACK, |
| trackGroup: SCROLLING_TRACK_GROUP, |
| params: trackConfig, |
| closeable, |
| }), |
| ]; |
| if (config?.pinned ?? true) { |
| actions.push(Actions.toggleTrackPinned({trackKey})); |
| } |
| return actions; |
| } |
| |
| export async function addPivotDebugSliceTracks( |
| engine: Engine, |
| data: SqlDataSource, |
| trackName: string, |
| sliceColumns: SliceColumns, |
| argColumns: string[], |
| config?: DebugTrackV2CreateConfig, |
| ) { |
| if (sliceColumns.pivot) { |
| // Get distinct values to group by |
| const pivotValues = await engine.query(` |
| with all_vals as (${data.sqlSource}) |
| select DISTINCT ${sliceColumns.pivot} from all_vals;`); |
| |
| const iter = pivotValues.iter({}); |
| |
| for (; iter.valid(); iter.next()) { |
| const pivotDataSource: SqlDataSource = { |
| sqlSource: `select * from |
| (${data.sqlSource}) |
| where ${sliceColumns.pivot} = '${iter.get(sliceColumns.pivot)}'`, |
| }; |
| |
| const actions = await createDebugSliceTrackActions( |
| engine, |
| pivotDataSource, |
| `${trackName.trim() || 'Pivot Track'}: ${iter.get(sliceColumns.pivot)}`, |
| sliceColumns, |
| argColumns, |
| config, |
| ); |
| |
| globals.dispatchMultiple(actions); |
| } |
| } |
| } |
| |
| // Adds a debug track immediately. Use createDebugSliceTrackActions() if you |
| // want to create many tracks at once. |
| export async function addDebugSliceTrack( |
| engine: Engine, |
| data: SqlDataSource, |
| trackName: string, |
| sliceColumns: SliceColumns, |
| argColumns: string[], |
| config?: DebugTrackV2CreateConfig, |
| ) { |
| const actions = await createDebugSliceTrackActions( |
| engine, |
| data, |
| trackName, |
| sliceColumns, |
| argColumns, |
| config, |
| ); |
| globals.dispatchMultiple(actions); |
| } |
| |
| // Names of the columns of the underlying view to be used as ts / dur / name. |
| export interface CounterColumns { |
| ts: string; |
| value: string; |
| } |
| |
| export interface CounterDebugTrackConfig { |
| data: SqlDataSource; |
| columns: CounterColumns; |
| } |
| |
| export interface CounterDebugTrackCreateConfig { |
| pinned?: boolean; // default true |
| closeable?: boolean; // default true |
| } |
| |
| // Creates actions to add a debug track. The actions must be dispatched to |
| // have an effect. Use this variant if you want to create many tracks at |
| // once or want to tweak the actions once produced. Otherwise, use |
| // addDebugCounterTrack(). |
| export async function createDebugCounterTrackActions( |
| data: SqlDataSource, |
| trackName: string, |
| columns: CounterColumns, |
| config?: CounterDebugTrackCreateConfig, |
| ) { |
| // To prepare displaying the provided data as a track, materialize it and |
| // compute depths. |
| const debugTrackId = ++debugTrackCount; |
| |
| const closeable = config?.closeable ?? true; |
| const params: CounterDebugTrackConfig = { |
| data, |
| columns, |
| }; |
| |
| const trackKey = uuidv4(); |
| const actions: DeferredAction<{}>[] = [ |
| Actions.addTrack({ |
| key: trackKey, |
| uri: DEBUG_COUNTER_TRACK_URI, |
| name: trackName.trim() || `Debug Track ${debugTrackId}`, |
| trackSortKey: PrimaryTrackSortKey.DEBUG_TRACK, |
| trackGroup: SCROLLING_TRACK_GROUP, |
| params, |
| closeable, |
| }), |
| ]; |
| if (config?.pinned ?? true) { |
| actions.push(Actions.toggleTrackPinned({trackKey})); |
| } |
| return actions; |
| } |
| |
| // Adds a debug track immediately. Use createDebugCounterTrackActions() if you |
| // want to create many tracks at once. |
| export async function addDebugCounterTrack( |
| data: SqlDataSource, |
| trackName: string, |
| columns: CounterColumns, |
| config?: CounterDebugTrackCreateConfig, |
| ) { |
| const actions = await createDebugCounterTrackActions( |
| data, |
| trackName, |
| columns, |
| config, |
| ); |
| globals.dispatchMultiple(actions); |
| } |