• 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 {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