1// Copyright (C) 2023 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import m from 'mithril'; 16 17import {Actions, DEBUG_SLICE_TRACK_KIND} from '../../common/actions'; 18import {EngineProxy} from '../../common/engine'; 19import {Selection} from '../../common/state'; 20import {OnSliceClickArgs} from '../../frontend/base_slice_track'; 21import {globals} from '../../frontend/globals'; 22import { 23 NamedSliceTrack, 24 NamedSliceTrackTypes, 25} from '../../frontend/named_slice_track'; 26import {NewTrackArgs} from '../../frontend/track'; 27import {TrackButton, TrackButtonAttrs} from '../../frontend/track_panel'; 28import {ARG_PREFIX} from './add_debug_track_menu'; 29 30// Names of the columns of the underlying view to be used as ts / dur / name. 31export interface SliceColumns { 32 ts: string; 33 dur: string; 34 name: string; 35} 36 37export interface DebugTrackV2Config { 38 sqlTableName: string; 39 columns: SliceColumns; 40} 41 42interface DebugTrackV2Types extends NamedSliceTrackTypes { 43 config: DebugTrackV2Config; 44} 45 46export class DebugTrackV2 extends NamedSliceTrack<DebugTrackV2Types> { 47 static readonly kind = DEBUG_SLICE_TRACK_KIND; 48 49 static create(args: NewTrackArgs) { 50 return new DebugTrackV2(args); 51 } 52 53 constructor(args: NewTrackArgs) { 54 super(args); 55 } 56 57 async initSqlTable(tableName: string): Promise<void> { 58 await this.engine.query(` 59 create view ${tableName} as 60 select 61 id, 62 ts, 63 dur, 64 name, 65 depth 66 from ${this.config.sqlTableName} 67 `); 68 } 69 70 isSelectionHandled(selection: Selection) { 71 if (selection.kind !== 'DEBUG_SLICE') { 72 return false; 73 } 74 return selection.sqlTableName === this.config.sqlTableName; 75 } 76 77 onSliceClick(args: OnSliceClickArgs<DebugTrackV2Types['slice']>) { 78 globals.dispatch(Actions.selectDebugSlice({ 79 id: args.slice.id, 80 sqlTableName: this.config.sqlTableName, 81 start: args.slice.start, 82 duration: args.slice.duration, 83 trackId: this.trackId, 84 })); 85 } 86 87 getTrackShellButtons(): Array<m.Vnode<TrackButtonAttrs>> { 88 return [m(TrackButton, { 89 action: () => { 90 globals.dispatch(Actions.removeDebugTrack({trackId: this.trackId})); 91 }, 92 i: 'close', 93 tooltip: 'Close', 94 showButton: true, 95 })]; 96 } 97} 98 99let debugTrackCount = 0; 100 101export async function addDebugTrack( 102 engine: EngineProxy, 103 sqlViewName: string, 104 trackName: string, 105 sliceColumns: SliceColumns, 106 argColumns: string[]) { 107 // QueryResultTab has successfully created a view corresponding to |uuid|. 108 // To prepare displaying it as a track, we materialize it and compute depths. 109 const debugTrackId = ++debugTrackCount; 110 const sqlTableName = `materialized_${debugTrackId}_${sqlViewName}`; 111 // TODO(altimin): Support removing this table when the track is closed. 112 await engine.query(` 113 create table ${sqlTableName} as 114 with prepared_data as ( 115 select 116 row_number() over () as id, 117 ${sliceColumns.ts} as ts, 118 cast(${sliceColumns.dur} as int) as dur, 119 printf('%s', ${sliceColumns.name}) as name 120 ${argColumns.length > 0 ? ',' : ''} 121 ${argColumns.map((c) => `${c} as ${ARG_PREFIX}${c}`).join(',')} 122 from ${sqlViewName} 123 ) 124 select 125 *, 126 internal_layout(ts, dur) over ( 127 order by ${sliceColumns.ts} 128 rows between unbounded preceding and current row 129 ) as depth 130 from prepared_data 131 order by ts;`); 132 133 globals.dispatch(Actions.addDebugTrack({ 134 engineId: engine.engineId, 135 name: trackName.trim() || `Debug Track ${debugTrackId}`, 136 config: { 137 sqlTableName, 138 columns: sliceColumns, 139 }, 140 })); 141} 142