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 m from 'mithril'; 16 17import {Actions} from '../common/actions'; 18import {globals} from './globals'; 19import {Button} from '../widgets/button'; 20import {Icons} from '../base/semantic_icons'; 21import {ThreadSliceTrack} from './thread_slice_track'; 22import {uuidv4Sql} from '../base/uuid'; 23import {Engine} from '../trace_processor/engine'; 24import {createView} from '../trace_processor/sql_utils'; 25 26export interface VisualizedArgsTrackAttrs { 27 readonly trackKey: string; 28 readonly engine: Engine; 29 readonly trackId: number; 30 readonly maxDepth: number; 31 readonly argName: string; 32} 33 34export class VisualisedArgsTrack extends ThreadSliceTrack { 35 private readonly viewName: string; 36 private readonly argName: string; 37 38 constructor({ 39 trackKey, 40 engine, 41 trackId, 42 maxDepth, 43 argName, 44 }: VisualizedArgsTrackAttrs) { 45 const uuid = uuidv4Sql(); 46 const escapedArgName = argName.replace(/[^a-zA-Z]/g, '_'); 47 const viewName = `__arg_visualisation_helper_${escapedArgName}_${uuid}_slice`; 48 49 super({engine, trackKey}, trackId, maxDepth, viewName); 50 this.viewName = viewName; 51 this.argName = argName; 52 } 53 54 async onInit() { 55 return await createView( 56 this.engine, 57 this.viewName, 58 ` 59 with slice_with_arg as ( 60 select 61 slice.id, 62 slice.track_id, 63 slice.ts, 64 slice.dur, 65 slice.thread_dur, 66 NULL as cat, 67 args.display_value as name 68 from slice 69 join args using (arg_set_id) 70 where args.key='${this.argName}' 71 ) 72 select 73 *, 74 (select count() 75 from ancestor_slice(s1.id) s2 76 join slice_with_arg s3 on s2.id=s3.id 77 ) as depth 78 from slice_with_arg s1 79 order by id 80 `, 81 ); 82 } 83 84 getTrackShellButtons(): m.Children { 85 return m(Button, { 86 onclick: () => { 87 // This behavior differs to the original behavior a little. 88 // Originally, hitting the close button on a single track removed ALL 89 // tracks with this argName, whereas this one only closes the single 90 // track. 91 // This will be easily fixable once we transition to using dynamic 92 // tracks instead of this "initial state" approach to add these tracks. 93 globals.dispatch(Actions.removeTracks({trackKeys: [this.trackKey]})); 94 }, 95 icon: Icons.Close, 96 title: 'Close', 97 compact: true, 98 }); 99 } 100} 101