• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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