• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2023 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 {
17  addDebugCounterTrack,
18  addDebugSliceTrack,
19} from '../../frontend/debug_tracks/debug_tracks';
20import {
21  BottomTabToSCSAdapter,
22  Plugin,
23  PluginContextTrace,
24  PluginDescriptor,
25} from '../../public';
26
27import {DebugSliceDetailsTab} from '../../frontend/debug_tracks/details_tab';
28import {GenericSliceDetailsTabConfig} from '../../frontend/generic_slice_details_tab';
29import {Optional, exists} from '../../base/utils';
30
31class DebugTracksPlugin implements Plugin {
32  async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
33    ctx.registerCommand({
34      id: 'perfetto.DebugTracks#addDebugSliceTrack',
35      name: 'Add debug slice track',
36      callback: async (arg: unknown) => {
37        // This command takes a query and creates a debug track out of it The
38        // query can be passed in using the first arg, or if this is not defined
39        // or is the wrong type, we prompt the user for it.
40        const query = await getStringFromArgOrPrompt(ctx, arg);
41        if (exists(query)) {
42          await addDebugSliceTrack(
43            ctx,
44            {
45              sqlSource: query,
46            },
47            'Debug slice track',
48            {ts: 'ts', dur: 'dur', name: 'name'},
49            [],
50          );
51        }
52      },
53    });
54
55    ctx.registerCommand({
56      id: 'perfetto.DebugTracks#addDebugCounterTrack',
57      name: 'Add debug counter track',
58      callback: async (arg: unknown) => {
59        const query = await getStringFromArgOrPrompt(ctx, arg);
60        if (exists(query)) {
61          await addDebugCounterTrack(
62            ctx,
63            {
64              sqlSource: query,
65            },
66            'Debug slice track',
67            {ts: 'ts', value: 'value'},
68          );
69        }
70      },
71    });
72
73    // TODO(stevegolton): While debug tracks are in their current state, we rely
74    // on this plugin to provide the details panel for them. In the future, this
75    // details panel will become part of the debug track's definition.
76    ctx.registerDetailsPanel(
77      new BottomTabToSCSAdapter({
78        tabFactory: (selection) => {
79          if (
80            selection.kind === 'GENERIC_SLICE' &&
81            selection.detailsPanelConfig.kind === DebugSliceDetailsTab.kind
82          ) {
83            const config = selection.detailsPanelConfig.config;
84            return new DebugSliceDetailsTab({
85              config: config as GenericSliceDetailsTabConfig,
86              engine: ctx.engine,
87              uuid: uuidv4(),
88            });
89          }
90          return undefined;
91        },
92      }),
93    );
94  }
95}
96
97// If arg is a string, return it, otherwise prompt the user for a string. An
98// exception is thrown if the prompt is cancelled, so this function handles this
99// and returns undefined in this case.
100async function getStringFromArgOrPrompt(
101  ctx: PluginContextTrace,
102  arg: unknown,
103): Promise<Optional<string>> {
104  if (typeof arg === 'string') {
105    return arg;
106  } else {
107    try {
108      return await ctx.prompt('Enter a query...');
109    } catch {
110      // Prompt was ignored
111      return undefined;
112    }
113  }
114}
115
116export const plugin: PluginDescriptor = {
117  pluginId: 'perfetto.DebugTracks',
118  plugin: DebugTracksPlugin,
119};
120