blob: 8e709f544b88b855c6b73e3285270efdc0ff46f1 [file] [log] [blame]
// Copyright (C) 2022 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 {v4 as uuidv4} from 'uuid';
import {Actions, AddTrackArgs} from '../common/actions';
import {Engine} from '../common/engine';
import {NUM} from '../common/query_result';
import {InThreadTrackSortKey} from '../common/state';
import {globals} from '../frontend/globals';
import {
VISUALISED_ARGS_SLICE_TRACK_KIND,
} from '../tracks/visualised_args/index';
import {Controller} from './controller';
export interface VisualisedArgControllerArgs {
argName: string;
engine: Engine;
}
export class VisualisedArgController extends Controller<'init'|'running'> {
private engine: Engine;
private argName: string;
private escapedArgName: string;
private tableName: string;
private addedTrackIds: string[];
constructor(args: VisualisedArgControllerArgs) {
super('init');
this.argName = args.argName;
this.engine = args.engine;
this.escapedArgName = this.argName.replace(/[^a-zA-Z]/g, '_');
this.tableName = `__arg_visualisation_helper_${this.escapedArgName}_slice`;
this.addedTrackIds = [];
}
onDestroy() {
this.engine.query(`drop table if exists ${this.tableName}`);
globals.dispatch(
Actions.removeVisualisedArgTracks({trackIds: this.addedTrackIds}));
}
async createTracks() {
const result = await this.engine.query(`
drop table if exists ${this.tableName};
create table ${this.tableName} as
with slice_with_arg as (
select
slice.id,
slice.track_id,
slice.ts,
slice.dur,
slice.thread_dur,
NULL as cat,
args.display_value as name
from slice
join args using (arg_set_id)
where args.key='${this.argName}'
)
select
*,
(select count()
from ancestor_slice(s1.id) s2
join slice_with_arg s3 on s2.id=s3.id
) as depth
from slice_with_arg s1
order by id;
select
track_id as trackId,
max(depth) as maxDepth
from ${this.tableName}
group by track_id;
`);
const tracksToAdd: AddTrackArgs[] = [];
const it = result.iter({'trackId': NUM, 'maxDepth': NUM});
for (; it.valid(); it.next()) {
const track =
globals.state
.tracks[globals.state.uiTrackIdByTraceTrackId[it.trackId]];
const utid = (track.trackSortKey as {utid?: number}).utid;
const id = uuidv4();
this.addedTrackIds.push(id);
tracksToAdd.push({
id,
trackGroup: track.trackGroup,
engineId: this.engine.id,
kind: VISUALISED_ARGS_SLICE_TRACK_KIND,
name: this.argName,
trackSortKey: utid === undefined ?
track.trackSortKey :
{utid, priority: InThreadTrackSortKey.VISUALISED_ARGS_TRACK},
config: {
maxDepth: it.maxDepth,
namespace: `__arg_visualisation_helper_${this.escapedArgName}`,
trackId: it.trackId,
argName: this.argName,
tid: (track.config as {tid?: number}).tid,
},
});
}
globals.dispatch(Actions.addTracks({tracks: tracksToAdd}));
globals.dispatch(Actions.sortThreadTracks({}));
}
run() {
switch (this.state) {
case 'init':
this.createTracks();
this.setState('running');
break;
case 'running':
// Nothing to do here.
break;
default:
throw new Error(`Unexpected state ${this.state}`);
}
}
}