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 {uuidv4} from '../../base/uuid'; 16import {NUM} from '../../trace_processor/query_result'; 17import {TrackNode} from '../../public/workspace'; 18import {Trace} from '../../public/trace'; 19import {SLICE_TRACK_KIND} from '../../public/track_kinds'; 20import {createVisualizedArgsTrack} from './visualized_args_track'; 21 22const VISUALIZED_ARGS_SLICE_TRACK_URI_PREFIX = 'perfetto.VisualizedArgs'; 23 24export async function addVisualizedArgTracks(trace: Trace, argName: string) { 25 const escapedArgName = argName.replace(/[^a-zA-Z]/g, '_'); 26 const tableName = `__arg_visualisation_helper_${escapedArgName}_slice`; 27 28 const result = await trace.engine.query(` 29 drop table if exists ${tableName}; 30 31 create table ${tableName} as 32 with slice_with_arg as ( 33 select 34 slice.id, 35 slice.track_id, 36 slice.ts, 37 slice.dur, 38 slice.thread_dur, 39 NULL as cat, 40 args.display_value as name 41 from slice 42 join args using (arg_set_id) 43 where args.key='${argName}' 44 ) 45 select 46 *, 47 (select count() 48 from ancestor_slice(s1.id) s2 49 join slice_with_arg s3 on s2.id=s3.id 50 ) as depth 51 from slice_with_arg s1 52 order by id; 53 54 select 55 track_id as trackId, 56 max(depth) as maxDepth 57 from ${tableName} 58 group by track_id; 59 `); 60 61 const addedTracks: TrackNode[] = []; 62 const it = result.iter({trackId: NUM, maxDepth: NUM}); 63 for (; it.valid(); it.next()) { 64 const trackId = it.trackId; 65 const maxDepth = it.maxDepth; 66 67 const uri = `${VISUALIZED_ARGS_SLICE_TRACK_URI_PREFIX}#${uuidv4()}`; 68 trace.tracks.registerTrack({ 69 uri, 70 title: argName, 71 chips: ['arg'], 72 track: await createVisualizedArgsTrack({ 73 trace, 74 uri, 75 trackId, 76 maxDepth, 77 argName, 78 onClose: () => { 79 // Remove all added for this argument 80 addedTracks.forEach((t) => t.parent?.removeChild(t)); 81 }, 82 }), 83 }); 84 85 // Find the thread slice track that corresponds with this trackID and insert 86 // this track before it. 87 const threadSliceTrack = trace.workspace.flatTracks.find((trackNode) => { 88 if (!trackNode.uri) return false; 89 const track = trace.tracks.getTrack(trackNode.uri); 90 return ( 91 track && 92 track.tags?.kind === SLICE_TRACK_KIND && 93 track.tags?.trackIds?.includes(trackId) 94 ); 95 }); 96 97 const parentGroup = threadSliceTrack?.parent; 98 if (parentGroup) { 99 const newTrack = new TrackNode({uri, title: argName}); 100 parentGroup.addChildBefore(newTrack, threadSliceTrack); 101 addedTracks.push(newTrack); 102 } 103 } 104} 105