xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.CriticalPath/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2024 The Android Open Source Project
2*6dbdd20aSAndroid Build Coastguard Worker//
3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*6dbdd20aSAndroid Build Coastguard Worker//
7*6dbdd20aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*6dbdd20aSAndroid Build Coastguard Worker//
9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License.
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Workerimport {getThreadInfo, ThreadInfo} from '../../components/sql_utils/thread';
16*6dbdd20aSAndroid Build Coastguard Workerimport {addDebugSliceTrack} from '../../components/tracks/debug_tracks';
17*6dbdd20aSAndroid Build Coastguard Workerimport {Trace} from '../../public/trace';
18*6dbdd20aSAndroid Build Coastguard Workerimport {THREAD_STATE_TRACK_KIND} from '../../public/track_kinds';
19*6dbdd20aSAndroid Build Coastguard Workerimport {PerfettoPlugin} from '../../public/plugin';
20*6dbdd20aSAndroid Build Coastguard Workerimport {asUtid, Utid} from '../../components/sql_utils/core_types';
21*6dbdd20aSAndroid Build Coastguard Workerimport {addQueryResultsTab} from '../../components/query_table/query_result_tab';
22*6dbdd20aSAndroid Build Coastguard Workerimport {showModal} from '../../widgets/modal';
23*6dbdd20aSAndroid Build Coastguard Workerimport {
24*6dbdd20aSAndroid Build Coastguard Worker  CRITICAL_PATH_CMD,
25*6dbdd20aSAndroid Build Coastguard Worker  CRITICAL_PATH_LITE_CMD,
26*6dbdd20aSAndroid Build Coastguard Worker} from '../../public/exposed_commands';
27*6dbdd20aSAndroid Build Coastguard Workerimport {getTimeSpanOfSelectionOrVisibleWindow} from '../../public/utils';
28*6dbdd20aSAndroid Build Coastguard Worker
29*6dbdd20aSAndroid Build Coastguard Workerconst criticalPathSliceColumns = {
30*6dbdd20aSAndroid Build Coastguard Worker  ts: 'ts',
31*6dbdd20aSAndroid Build Coastguard Worker  dur: 'dur',
32*6dbdd20aSAndroid Build Coastguard Worker  name: 'name',
33*6dbdd20aSAndroid Build Coastguard Worker};
34*6dbdd20aSAndroid Build Coastguard Worker
35*6dbdd20aSAndroid Build Coastguard Workerconst criticalPathsliceColumnNames = [
36*6dbdd20aSAndroid Build Coastguard Worker  'id',
37*6dbdd20aSAndroid Build Coastguard Worker  'utid',
38*6dbdd20aSAndroid Build Coastguard Worker  'ts',
39*6dbdd20aSAndroid Build Coastguard Worker  'dur',
40*6dbdd20aSAndroid Build Coastguard Worker  'name',
41*6dbdd20aSAndroid Build Coastguard Worker  'table_name',
42*6dbdd20aSAndroid Build Coastguard Worker];
43*6dbdd20aSAndroid Build Coastguard Worker
44*6dbdd20aSAndroid Build Coastguard Workerconst criticalPathsliceLiteColumns = {
45*6dbdd20aSAndroid Build Coastguard Worker  ts: 'ts',
46*6dbdd20aSAndroid Build Coastguard Worker  dur: 'dur',
47*6dbdd20aSAndroid Build Coastguard Worker  name: 'thread_name',
48*6dbdd20aSAndroid Build Coastguard Worker};
49*6dbdd20aSAndroid Build Coastguard Worker
50*6dbdd20aSAndroid Build Coastguard Workerconst criticalPathsliceLiteColumnNames = [
51*6dbdd20aSAndroid Build Coastguard Worker  'id',
52*6dbdd20aSAndroid Build Coastguard Worker  'utid',
53*6dbdd20aSAndroid Build Coastguard Worker  'ts',
54*6dbdd20aSAndroid Build Coastguard Worker  'dur',
55*6dbdd20aSAndroid Build Coastguard Worker  'thread_name',
56*6dbdd20aSAndroid Build Coastguard Worker  'process_name',
57*6dbdd20aSAndroid Build Coastguard Worker  'table_name',
58*6dbdd20aSAndroid Build Coastguard Worker];
59*6dbdd20aSAndroid Build Coastguard Worker
60*6dbdd20aSAndroid Build Coastguard Workerconst sliceLiteColumns = {ts: 'ts', dur: 'dur', name: 'thread_name'};
61*6dbdd20aSAndroid Build Coastguard Worker
62*6dbdd20aSAndroid Build Coastguard Workerconst sliceLiteColumnNames = [
63*6dbdd20aSAndroid Build Coastguard Worker  'id',
64*6dbdd20aSAndroid Build Coastguard Worker  'utid',
65*6dbdd20aSAndroid Build Coastguard Worker  'ts',
66*6dbdd20aSAndroid Build Coastguard Worker  'dur',
67*6dbdd20aSAndroid Build Coastguard Worker  'thread_name',
68*6dbdd20aSAndroid Build Coastguard Worker  'process_name',
69*6dbdd20aSAndroid Build Coastguard Worker  'table_name',
70*6dbdd20aSAndroid Build Coastguard Worker];
71*6dbdd20aSAndroid Build Coastguard Worker
72*6dbdd20aSAndroid Build Coastguard Workerconst sliceColumns = {ts: 'ts', dur: 'dur', name: 'name'};
73*6dbdd20aSAndroid Build Coastguard Worker
74*6dbdd20aSAndroid Build Coastguard Workerconst sliceColumnNames = ['id', 'utid', 'ts', 'dur', 'name', 'table_name'];
75*6dbdd20aSAndroid Build Coastguard Worker
76*6dbdd20aSAndroid Build Coastguard Workerfunction getFirstUtidOfSelectionOrVisibleWindow(trace: Trace): number {
77*6dbdd20aSAndroid Build Coastguard Worker  const selection = trace.selection.selection;
78*6dbdd20aSAndroid Build Coastguard Worker  if (selection.kind === 'area') {
79*6dbdd20aSAndroid Build Coastguard Worker    for (const trackDesc of selection.tracks) {
80*6dbdd20aSAndroid Build Coastguard Worker      if (
81*6dbdd20aSAndroid Build Coastguard Worker        trackDesc?.tags?.kind === THREAD_STATE_TRACK_KIND &&
82*6dbdd20aSAndroid Build Coastguard Worker        trackDesc?.tags?.utid !== undefined
83*6dbdd20aSAndroid Build Coastguard Worker      ) {
84*6dbdd20aSAndroid Build Coastguard Worker        return trackDesc.tags.utid;
85*6dbdd20aSAndroid Build Coastguard Worker      }
86*6dbdd20aSAndroid Build Coastguard Worker    }
87*6dbdd20aSAndroid Build Coastguard Worker  }
88*6dbdd20aSAndroid Build Coastguard Worker
89*6dbdd20aSAndroid Build Coastguard Worker  return 0;
90*6dbdd20aSAndroid Build Coastguard Worker}
91*6dbdd20aSAndroid Build Coastguard Worker
92*6dbdd20aSAndroid Build Coastguard Workerfunction showModalErrorAreaSelectionRequired() {
93*6dbdd20aSAndroid Build Coastguard Worker  showModal({
94*6dbdd20aSAndroid Build Coastguard Worker    title: 'Error: range selection required',
95*6dbdd20aSAndroid Build Coastguard Worker    content:
96*6dbdd20aSAndroid Build Coastguard Worker      'This command requires an area selection over a thread state track.',
97*6dbdd20aSAndroid Build Coastguard Worker  });
98*6dbdd20aSAndroid Build Coastguard Worker}
99*6dbdd20aSAndroid Build Coastguard Worker
100*6dbdd20aSAndroid Build Coastguard Workerfunction showModalErrorThreadStateRequired() {
101*6dbdd20aSAndroid Build Coastguard Worker  showModal({
102*6dbdd20aSAndroid Build Coastguard Worker    title: 'Error: thread state selection required',
103*6dbdd20aSAndroid Build Coastguard Worker    content: 'This command requires a thread state slice to be selected.',
104*6dbdd20aSAndroid Build Coastguard Worker  });
105*6dbdd20aSAndroid Build Coastguard Worker}
106*6dbdd20aSAndroid Build Coastguard Worker
107*6dbdd20aSAndroid Build Coastguard Worker// If utid is undefined, returns the utid for the selected thread state track,
108*6dbdd20aSAndroid Build Coastguard Worker// if any. If it's defined, looks up the info about that specific utid.
109*6dbdd20aSAndroid Build Coastguard Workerasync function getThreadInfoForUtidOrSelection(
110*6dbdd20aSAndroid Build Coastguard Worker  trace: Trace,
111*6dbdd20aSAndroid Build Coastguard Worker  utid?: Utid,
112*6dbdd20aSAndroid Build Coastguard Worker): Promise<ThreadInfo | undefined> {
113*6dbdd20aSAndroid Build Coastguard Worker  if (utid === undefined) {
114*6dbdd20aSAndroid Build Coastguard Worker    const selection = trace.selection.selection;
115*6dbdd20aSAndroid Build Coastguard Worker    if (selection.kind === 'track_event') {
116*6dbdd20aSAndroid Build Coastguard Worker      if (selection.utid !== undefined) {
117*6dbdd20aSAndroid Build Coastguard Worker        utid = asUtid(selection.utid);
118*6dbdd20aSAndroid Build Coastguard Worker      }
119*6dbdd20aSAndroid Build Coastguard Worker    }
120*6dbdd20aSAndroid Build Coastguard Worker  }
121*6dbdd20aSAndroid Build Coastguard Worker  if (utid === undefined) return undefined;
122*6dbdd20aSAndroid Build Coastguard Worker  return getThreadInfo(trace.engine, utid);
123*6dbdd20aSAndroid Build Coastguard Worker}
124*6dbdd20aSAndroid Build Coastguard Worker
125*6dbdd20aSAndroid Build Coastguard Workerexport default class implements PerfettoPlugin {
126*6dbdd20aSAndroid Build Coastguard Worker  static readonly id = 'dev.perfetto.CriticalPath';
127*6dbdd20aSAndroid Build Coastguard Worker  async onTraceLoad(ctx: Trace): Promise<void> {
128*6dbdd20aSAndroid Build Coastguard Worker    // The 3 commands below are used in two contextes:
129*6dbdd20aSAndroid Build Coastguard Worker    // 1. By clicking a slice and using the command palette. In this case the
130*6dbdd20aSAndroid Build Coastguard Worker    //    utid argument is undefined and we need to look at the selection.
131*6dbdd20aSAndroid Build Coastguard Worker    // 2. Invoked via runCommand(...) by thread_state_tab.ts when the user
132*6dbdd20aSAndroid Build Coastguard Worker    //    clicks on the buttons in the details panel. In this case the details
133*6dbdd20aSAndroid Build Coastguard Worker    //    panel passes the utid explicitly.
134*6dbdd20aSAndroid Build Coastguard Worker    ctx.commands.registerCommand({
135*6dbdd20aSAndroid Build Coastguard Worker      id: CRITICAL_PATH_LITE_CMD,
136*6dbdd20aSAndroid Build Coastguard Worker      name: 'Critical path lite (selected thread state slice)',
137*6dbdd20aSAndroid Build Coastguard Worker      callback: async (utid?: Utid) => {
138*6dbdd20aSAndroid Build Coastguard Worker        const thdInfo = await getThreadInfoForUtidOrSelection(ctx, utid);
139*6dbdd20aSAndroid Build Coastguard Worker        if (thdInfo === undefined) {
140*6dbdd20aSAndroid Build Coastguard Worker          return showModalErrorThreadStateRequired();
141*6dbdd20aSAndroid Build Coastguard Worker        }
142*6dbdd20aSAndroid Build Coastguard Worker        ctx.engine
143*6dbdd20aSAndroid Build Coastguard Worker          .query(`INCLUDE PERFETTO MODULE sched.thread_executing_span;`)
144*6dbdd20aSAndroid Build Coastguard Worker          .then(() =>
145*6dbdd20aSAndroid Build Coastguard Worker            addDebugSliceTrack({
146*6dbdd20aSAndroid Build Coastguard Worker              trace: ctx,
147*6dbdd20aSAndroid Build Coastguard Worker              data: {
148*6dbdd20aSAndroid Build Coastguard Worker                sqlSource: `
149*6dbdd20aSAndroid Build Coastguard Worker                SELECT
150*6dbdd20aSAndroid Build Coastguard Worker                  cr.id,
151*6dbdd20aSAndroid Build Coastguard Worker                  cr.utid,
152*6dbdd20aSAndroid Build Coastguard Worker                  cr.ts,
153*6dbdd20aSAndroid Build Coastguard Worker                  cr.dur,
154*6dbdd20aSAndroid Build Coastguard Worker                  thread.name AS thread_name,
155*6dbdd20aSAndroid Build Coastguard Worker                  process.name AS process_name,
156*6dbdd20aSAndroid Build Coastguard Worker                  'thread_state' AS table_name
157*6dbdd20aSAndroid Build Coastguard Worker                FROM
158*6dbdd20aSAndroid Build Coastguard Worker                  _thread_executing_span_critical_path(
159*6dbdd20aSAndroid Build Coastguard Worker                    ${thdInfo.utid},
160*6dbdd20aSAndroid Build Coastguard Worker                    trace_bounds.start_ts,
161*6dbdd20aSAndroid Build Coastguard Worker                    trace_bounds.end_ts - trace_bounds.start_ts) cr,
162*6dbdd20aSAndroid Build Coastguard Worker                  trace_bounds
163*6dbdd20aSAndroid Build Coastguard Worker                JOIN thread USING(utid)
164*6dbdd20aSAndroid Build Coastguard Worker                JOIN process USING(upid)
165*6dbdd20aSAndroid Build Coastguard Worker              `,
166*6dbdd20aSAndroid Build Coastguard Worker                columns: sliceLiteColumnNames,
167*6dbdd20aSAndroid Build Coastguard Worker              },
168*6dbdd20aSAndroid Build Coastguard Worker              title: `${thdInfo.name}`,
169*6dbdd20aSAndroid Build Coastguard Worker              columns: sliceLiteColumns,
170*6dbdd20aSAndroid Build Coastguard Worker              argColumns: sliceLiteColumnNames,
171*6dbdd20aSAndroid Build Coastguard Worker            }),
172*6dbdd20aSAndroid Build Coastguard Worker          );
173*6dbdd20aSAndroid Build Coastguard Worker      },
174*6dbdd20aSAndroid Build Coastguard Worker    });
175*6dbdd20aSAndroid Build Coastguard Worker
176*6dbdd20aSAndroid Build Coastguard Worker    ctx.commands.registerCommand({
177*6dbdd20aSAndroid Build Coastguard Worker      id: CRITICAL_PATH_CMD,
178*6dbdd20aSAndroid Build Coastguard Worker      name: 'Critical path (selected thread state slice)',
179*6dbdd20aSAndroid Build Coastguard Worker      callback: async (utid?: Utid) => {
180*6dbdd20aSAndroid Build Coastguard Worker        const thdInfo = await getThreadInfoForUtidOrSelection(ctx, utid);
181*6dbdd20aSAndroid Build Coastguard Worker        if (thdInfo === undefined) {
182*6dbdd20aSAndroid Build Coastguard Worker          return showModalErrorThreadStateRequired();
183*6dbdd20aSAndroid Build Coastguard Worker        }
184*6dbdd20aSAndroid Build Coastguard Worker        ctx.engine
185*6dbdd20aSAndroid Build Coastguard Worker          .query(
186*6dbdd20aSAndroid Build Coastguard Worker            `INCLUDE PERFETTO MODULE sched.thread_executing_span_with_slice;`,
187*6dbdd20aSAndroid Build Coastguard Worker          )
188*6dbdd20aSAndroid Build Coastguard Worker          .then(() =>
189*6dbdd20aSAndroid Build Coastguard Worker            addDebugSliceTrack({
190*6dbdd20aSAndroid Build Coastguard Worker              trace: ctx,
191*6dbdd20aSAndroid Build Coastguard Worker              data: {
192*6dbdd20aSAndroid Build Coastguard Worker                sqlSource: `
193*6dbdd20aSAndroid Build Coastguard Worker                SELECT cr.id, cr.utid, cr.ts, cr.dur, cr.name, cr.table_name
194*6dbdd20aSAndroid Build Coastguard Worker                  FROM
195*6dbdd20aSAndroid Build Coastguard Worker                    _thread_executing_span_critical_path_stack(
196*6dbdd20aSAndroid Build Coastguard Worker                      ${thdInfo.utid},
197*6dbdd20aSAndroid Build Coastguard Worker                      trace_bounds.start_ts,
198*6dbdd20aSAndroid Build Coastguard Worker                      trace_bounds.end_ts - trace_bounds.start_ts) cr,
199*6dbdd20aSAndroid Build Coastguard Worker                    trace_bounds WHERE name IS NOT NULL
200*6dbdd20aSAndroid Build Coastguard Worker              `,
201*6dbdd20aSAndroid Build Coastguard Worker                columns: sliceColumnNames,
202*6dbdd20aSAndroid Build Coastguard Worker              },
203*6dbdd20aSAndroid Build Coastguard Worker              title: `${thdInfo.name}`,
204*6dbdd20aSAndroid Build Coastguard Worker              columns: sliceColumns,
205*6dbdd20aSAndroid Build Coastguard Worker              argColumns: sliceColumnNames,
206*6dbdd20aSAndroid Build Coastguard Worker            }),
207*6dbdd20aSAndroid Build Coastguard Worker          );
208*6dbdd20aSAndroid Build Coastguard Worker      },
209*6dbdd20aSAndroid Build Coastguard Worker    });
210*6dbdd20aSAndroid Build Coastguard Worker
211*6dbdd20aSAndroid Build Coastguard Worker    ctx.commands.registerCommand({
212*6dbdd20aSAndroid Build Coastguard Worker      id: 'perfetto.CriticalPathLite_AreaSelection',
213*6dbdd20aSAndroid Build Coastguard Worker      name: 'Critical path lite (over area selection)',
214*6dbdd20aSAndroid Build Coastguard Worker      callback: async () => {
215*6dbdd20aSAndroid Build Coastguard Worker        const trackUtid = getFirstUtidOfSelectionOrVisibleWindow(ctx);
216*6dbdd20aSAndroid Build Coastguard Worker        const window = await getTimeSpanOfSelectionOrVisibleWindow(ctx);
217*6dbdd20aSAndroid Build Coastguard Worker        if (trackUtid === 0) {
218*6dbdd20aSAndroid Build Coastguard Worker          return showModalErrorAreaSelectionRequired();
219*6dbdd20aSAndroid Build Coastguard Worker        }
220*6dbdd20aSAndroid Build Coastguard Worker        await ctx.engine.query(
221*6dbdd20aSAndroid Build Coastguard Worker          `INCLUDE PERFETTO MODULE sched.thread_executing_span;`,
222*6dbdd20aSAndroid Build Coastguard Worker        );
223*6dbdd20aSAndroid Build Coastguard Worker        await addDebugSliceTrack({
224*6dbdd20aSAndroid Build Coastguard Worker          trace: ctx,
225*6dbdd20aSAndroid Build Coastguard Worker          data: {
226*6dbdd20aSAndroid Build Coastguard Worker            sqlSource: `
227*6dbdd20aSAndroid Build Coastguard Worker                SELECT
228*6dbdd20aSAndroid Build Coastguard Worker                  cr.id,
229*6dbdd20aSAndroid Build Coastguard Worker                  cr.utid,
230*6dbdd20aSAndroid Build Coastguard Worker                  cr.ts,
231*6dbdd20aSAndroid Build Coastguard Worker                  cr.dur,
232*6dbdd20aSAndroid Build Coastguard Worker                  thread.name AS thread_name,
233*6dbdd20aSAndroid Build Coastguard Worker                  process.name AS process_name,
234*6dbdd20aSAndroid Build Coastguard Worker                  'thread_state' AS table_name
235*6dbdd20aSAndroid Build Coastguard Worker                FROM
236*6dbdd20aSAndroid Build Coastguard Worker                  _thread_executing_span_critical_path(
237*6dbdd20aSAndroid Build Coastguard Worker                      ${trackUtid},
238*6dbdd20aSAndroid Build Coastguard Worker                      ${window.start},
239*6dbdd20aSAndroid Build Coastguard Worker                      ${window.end} - ${window.start}) cr
240*6dbdd20aSAndroid Build Coastguard Worker                JOIN thread USING(utid)
241*6dbdd20aSAndroid Build Coastguard Worker                JOIN process USING(upid)
242*6dbdd20aSAndroid Build Coastguard Worker                `,
243*6dbdd20aSAndroid Build Coastguard Worker            columns: criticalPathsliceLiteColumnNames,
244*6dbdd20aSAndroid Build Coastguard Worker          },
245*6dbdd20aSAndroid Build Coastguard Worker          title:
246*6dbdd20aSAndroid Build Coastguard Worker            (await getThreadInfo(ctx.engine, trackUtid as Utid)).name ??
247*6dbdd20aSAndroid Build Coastguard Worker            '<thread name>',
248*6dbdd20aSAndroid Build Coastguard Worker          columns: criticalPathsliceLiteColumns,
249*6dbdd20aSAndroid Build Coastguard Worker          argColumns: criticalPathsliceLiteColumnNames,
250*6dbdd20aSAndroid Build Coastguard Worker        });
251*6dbdd20aSAndroid Build Coastguard Worker      },
252*6dbdd20aSAndroid Build Coastguard Worker    });
253*6dbdd20aSAndroid Build Coastguard Worker
254*6dbdd20aSAndroid Build Coastguard Worker    ctx.commands.registerCommand({
255*6dbdd20aSAndroid Build Coastguard Worker      id: 'perfetto.CriticalPath_AreaSelection',
256*6dbdd20aSAndroid Build Coastguard Worker      name: 'Critical path  (over area selection)',
257*6dbdd20aSAndroid Build Coastguard Worker      callback: async () => {
258*6dbdd20aSAndroid Build Coastguard Worker        const trackUtid = getFirstUtidOfSelectionOrVisibleWindow(ctx);
259*6dbdd20aSAndroid Build Coastguard Worker        const window = await getTimeSpanOfSelectionOrVisibleWindow(ctx);
260*6dbdd20aSAndroid Build Coastguard Worker        if (trackUtid === 0) {
261*6dbdd20aSAndroid Build Coastguard Worker          return showModalErrorAreaSelectionRequired();
262*6dbdd20aSAndroid Build Coastguard Worker        }
263*6dbdd20aSAndroid Build Coastguard Worker        await ctx.engine.query(
264*6dbdd20aSAndroid Build Coastguard Worker          `INCLUDE PERFETTO MODULE sched.thread_executing_span_with_slice;`,
265*6dbdd20aSAndroid Build Coastguard Worker        );
266*6dbdd20aSAndroid Build Coastguard Worker        await addDebugSliceTrack({
267*6dbdd20aSAndroid Build Coastguard Worker          trace: ctx,
268*6dbdd20aSAndroid Build Coastguard Worker          data: {
269*6dbdd20aSAndroid Build Coastguard Worker            sqlSource: `
270*6dbdd20aSAndroid Build Coastguard Worker                SELECT cr.id, cr.utid, cr.ts, cr.dur, cr.name, cr.table_name
271*6dbdd20aSAndroid Build Coastguard Worker                FROM
272*6dbdd20aSAndroid Build Coastguard Worker                _critical_path_stack(
273*6dbdd20aSAndroid Build Coastguard Worker                  ${trackUtid},
274*6dbdd20aSAndroid Build Coastguard Worker                  ${window.start},
275*6dbdd20aSAndroid Build Coastguard Worker                  ${window.end} - ${window.start}, 1, 1, 1, 1) cr
276*6dbdd20aSAndroid Build Coastguard Worker                WHERE name IS NOT NULL
277*6dbdd20aSAndroid Build Coastguard Worker                `,
278*6dbdd20aSAndroid Build Coastguard Worker            columns: criticalPathsliceColumnNames,
279*6dbdd20aSAndroid Build Coastguard Worker          },
280*6dbdd20aSAndroid Build Coastguard Worker          title:
281*6dbdd20aSAndroid Build Coastguard Worker            (await getThreadInfo(ctx.engine, trackUtid as Utid)).name ??
282*6dbdd20aSAndroid Build Coastguard Worker            '<thread name>',
283*6dbdd20aSAndroid Build Coastguard Worker          columns: criticalPathSliceColumns,
284*6dbdd20aSAndroid Build Coastguard Worker          argColumns: criticalPathsliceColumnNames,
285*6dbdd20aSAndroid Build Coastguard Worker        });
286*6dbdd20aSAndroid Build Coastguard Worker      },
287*6dbdd20aSAndroid Build Coastguard Worker    });
288*6dbdd20aSAndroid Build Coastguard Worker
289*6dbdd20aSAndroid Build Coastguard Worker    ctx.commands.registerCommand({
290*6dbdd20aSAndroid Build Coastguard Worker      id: 'perfetto.CriticalPathPprof_AreaSelection',
291*6dbdd20aSAndroid Build Coastguard Worker      name: 'Critical path pprof (over area selection)',
292*6dbdd20aSAndroid Build Coastguard Worker      callback: async () => {
293*6dbdd20aSAndroid Build Coastguard Worker        const trackUtid = getFirstUtidOfSelectionOrVisibleWindow(ctx);
294*6dbdd20aSAndroid Build Coastguard Worker        const window = await getTimeSpanOfSelectionOrVisibleWindow(ctx);
295*6dbdd20aSAndroid Build Coastguard Worker        if (trackUtid === 0) {
296*6dbdd20aSAndroid Build Coastguard Worker          return showModalErrorAreaSelectionRequired();
297*6dbdd20aSAndroid Build Coastguard Worker        }
298*6dbdd20aSAndroid Build Coastguard Worker        addQueryResultsTab(ctx, {
299*6dbdd20aSAndroid Build Coastguard Worker          query: `
300*6dbdd20aSAndroid Build Coastguard Worker              INCLUDE PERFETTO MODULE sched.thread_executing_span_with_slice;
301*6dbdd20aSAndroid Build Coastguard Worker              SELECT *
302*6dbdd20aSAndroid Build Coastguard Worker                FROM
303*6dbdd20aSAndroid Build Coastguard Worker                  _thread_executing_span_critical_path_graph(
304*6dbdd20aSAndroid Build Coastguard Worker                  "criical_path",
305*6dbdd20aSAndroid Build Coastguard Worker                    ${trackUtid},
306*6dbdd20aSAndroid Build Coastguard Worker                    ${window.start},
307*6dbdd20aSAndroid Build Coastguard Worker                    ${window.end} - ${window.start}) cr`,
308*6dbdd20aSAndroid Build Coastguard Worker          title: 'Critical path',
309*6dbdd20aSAndroid Build Coastguard Worker        });
310*6dbdd20aSAndroid Build Coastguard Worker      },
311*6dbdd20aSAndroid Build Coastguard Worker    });
312*6dbdd20aSAndroid Build Coastguard Worker  }
313*6dbdd20aSAndroid Build Coastguard Worker}
314