• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 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 {Engine, TrackContext} from '../public';
16import {
17  CustomSqlDetailsPanelConfig,
18  CustomSqlTableDefConfig,
19  CustomSqlTableSliceTrack,
20} from './tracks/custom_sql_table_slice_track';
21import {NamedSliceTrackTypes} from './named_slice_track';
22import {SliceColumns, SqlDataSource} from './debug_tracks/debug_tracks';
23import {uuidv4Sql} from '../base/uuid';
24import {ARG_PREFIX, DebugSliceDetailsTab} from './debug_tracks/details_tab';
25import {createPerfettoTable} from '../trace_processor/sql_utils';
26
27export interface SimpleSliceTrackConfig {
28  data: SqlDataSource;
29  columns: SliceColumns;
30  argColumns: string[];
31}
32
33export class SimpleSliceTrack extends CustomSqlTableSliceTrack<NamedSliceTrackTypes> {
34  private config: SimpleSliceTrackConfig;
35  private sqlTableName: string;
36
37  constructor(
38    engine: Engine,
39    ctx: TrackContext,
40    config: SimpleSliceTrackConfig,
41  ) {
42    super({
43      engine,
44      trackKey: ctx.trackKey,
45    });
46
47    this.config = config;
48    this.sqlTableName = `__simple_slice_${uuidv4Sql(ctx.trackKey)}`;
49  }
50
51  async getSqlDataSource(): Promise<CustomSqlTableDefConfig> {
52    const table = await createPerfettoTable(
53      this.engine,
54      this.sqlTableName,
55      this.createTableQuery(
56        this.config.data,
57        this.config.columns,
58        this.config.argColumns,
59      ),
60    );
61    return {
62      sqlTableName: this.sqlTableName,
63      disposable: table,
64    };
65  }
66
67  getDetailsPanel(): CustomSqlDetailsPanelConfig {
68    // We currently borrow the debug slice details tab.
69    // TODO: Don't do this!
70    return {
71      kind: DebugSliceDetailsTab.kind,
72      config: {
73        sqlTableName: this.sqlTableName,
74        title: 'Debug Slice',
75      },
76    };
77  }
78
79  private createTableQuery(
80    data: SqlDataSource,
81    sliceColumns: SliceColumns,
82    argColumns: string[],
83  ): string {
84    // If the view has clashing names (e.g. "name" coming from joining two
85    // different tables, we will see names like "name_1", "name_2", but they
86    // won't be addressable from the SQL. So we explicitly name them through a
87    // list of columns passed to CTE.
88    const dataColumns =
89      data.columns !== undefined ? `(${data.columns.join(', ')})` : '';
90
91    // TODO(altimin): Support removing this table when the track is closed.
92    const dur = sliceColumns.dur === '0' ? 0 : sliceColumns.dur;
93    return `
94      with data${dataColumns} as (
95        ${data.sqlSource}
96      ),
97      prepared_data as (
98        select
99          ${sliceColumns.ts} as ts,
100          ifnull(cast(${dur} as int), -1) as dur,
101          printf('%s', ${sliceColumns.name}) as name
102          ${argColumns.length > 0 ? ',' : ''}
103          ${argColumns.map((c) => `${c} as ${ARG_PREFIX}${c}`).join(',\n')}
104        from data
105      )
106      select
107        row_number() over (order by ts) as id,
108        *
109      from prepared_data
110      order by ts
111    `;
112  }
113}
114