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