• 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 {assertExists} from '../base/logging';
16import {uuidv4} from '../base/uuid';
17import {Actions, AddTrackArgs} from '../common/actions';
18import {InThreadTrackSortKey} from '../common/state';
19import {Engine, NUM, TrackDescriptor} from '../public';
20import {globals} from './globals';
21import {VisualisedArgsTrack} from './visualized_args_track';
22
23const VISUALISED_ARGS_SLICE_TRACK_URI_PREFIX = 'perfetto.VisualisedArgs';
24
25// We need to add tracks from the core and from plugins. In order to add a debug
26// track we need to pass a context through with we can add the track. This is
27// different for plugins vs the core. This interface defines the generic shape
28// of this context, which can be supplied from a plugin or built from globals.
29//
30// TODO(stevegolton): In the future, both the core and plugins should have
31// access to some Context object which implements the various things we want to
32// do in a generic way, so that we don't have to do this mangling to get this to
33// work.
34interface Context {
35  engine: Engine;
36  registerTrack(track: TrackDescriptor): unknown;
37}
38
39export async function addVisualisedArgTracks(ctx: Context, argName: string) {
40  const escapedArgName = argName.replace(/[^a-zA-Z]/g, '_');
41  const tableName = `__arg_visualisation_helper_${escapedArgName}_slice`;
42
43  const result = await ctx.engine.query(`
44        drop table if exists ${tableName};
45
46        create table ${tableName} as
47        with slice_with_arg as (
48          select
49            slice.id,
50            slice.track_id,
51            slice.ts,
52            slice.dur,
53            slice.thread_dur,
54            NULL as cat,
55            args.display_value as name
56          from slice
57          join args using (arg_set_id)
58          where args.key='${argName}'
59        )
60        select
61          *,
62          (select count()
63           from ancestor_slice(s1.id) s2
64           join slice_with_arg s3 on s2.id=s3.id
65          ) as depth
66        from slice_with_arg s1
67        order by id;
68
69        select
70          track_id as trackId,
71          max(depth) as maxDepth
72        from ${tableName}
73        group by track_id;
74    `);
75
76  const tracksToAdd: AddTrackArgs[] = [];
77  const it = result.iter({trackId: NUM, maxDepth: NUM});
78  const addedTrackKeys: string[] = [];
79  for (; it.valid(); it.next()) {
80    const trackId = it.trackId;
81    const maxDepth = it.maxDepth;
82    const trackKey = globals.trackManager.trackKeyByTrackId.get(trackId);
83    const track = globals.state.tracks[assertExists(trackKey)];
84    const utid = (track.trackSortKey as {utid?: number}).utid;
85    const key = uuidv4();
86    addedTrackKeys.push(key);
87
88    const uri = `${VISUALISED_ARGS_SLICE_TRACK_URI_PREFIX}#${uuidv4()}`;
89    ctx.registerTrack({
90      uri,
91      tags: {
92        metric: true, // TODO(stevegolton): Is this track really a metric?
93      },
94      trackFactory: (trackCtx) => {
95        return new VisualisedArgsTrack({
96          engine: ctx.engine,
97          trackKey: trackCtx.trackKey,
98          trackId,
99          maxDepth,
100          argName,
101        });
102      },
103    });
104
105    tracksToAdd.push({
106      key,
107      trackGroup: track.trackGroup,
108      name: argName,
109      trackSortKey:
110        utid === undefined
111          ? track.trackSortKey
112          : {utid, priority: InThreadTrackSortKey.VISUALISED_ARGS_TRACK},
113      uri,
114    });
115  }
116
117  globals.dispatchMultiple([
118    Actions.addTracks({tracks: tracksToAdd}),
119    Actions.sortThreadTracks({}),
120  ]);
121}
122