xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.Counter/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2021 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 {
16*6dbdd20aSAndroid Build Coastguard Worker  NUM_NULL,
17*6dbdd20aSAndroid Build Coastguard Worker  STR_NULL,
18*6dbdd20aSAndroid Build Coastguard Worker  LONG_NULL,
19*6dbdd20aSAndroid Build Coastguard Worker  NUM,
20*6dbdd20aSAndroid Build Coastguard Worker  STR,
21*6dbdd20aSAndroid Build Coastguard Worker} from '../../trace_processor/query_result';
22*6dbdd20aSAndroid Build Coastguard Workerimport {Trace} from '../../public/trace';
23*6dbdd20aSAndroid Build Coastguard Workerimport {COUNTER_TRACK_KIND} from '../../public/track_kinds';
24*6dbdd20aSAndroid Build Coastguard Workerimport {PerfettoPlugin} from '../../public/plugin';
25*6dbdd20aSAndroid Build Coastguard Workerimport {getThreadUriPrefix, getTrackName} from '../../public/utils';
26*6dbdd20aSAndroid Build Coastguard Workerimport {CounterOptions} from '../../components/tracks/base_counter_track';
27*6dbdd20aSAndroid Build Coastguard Workerimport {TraceProcessorCounterTrack} from './trace_processor_counter_track';
28*6dbdd20aSAndroid Build Coastguard Workerimport {exists} from '../../base/utils';
29*6dbdd20aSAndroid Build Coastguard Workerimport {TrackNode} from '../../public/workspace';
30*6dbdd20aSAndroid Build Coastguard Workerimport {CounterSelectionAggregator} from './counter_selection_aggregator';
31*6dbdd20aSAndroid Build Coastguard Workerimport ProcessThreadGroupsPlugin from '../dev.perfetto.ProcessThreadGroups';
32*6dbdd20aSAndroid Build Coastguard Worker
33*6dbdd20aSAndroid Build Coastguard Workerconst NETWORK_TRACK_REGEX = new RegExp('^.* (Received|Transmitted)( KB)?$');
34*6dbdd20aSAndroid Build Coastguard Workerconst ENTITY_RESIDENCY_REGEX = new RegExp('^Entity residency:');
35*6dbdd20aSAndroid Build Coastguard Worker
36*6dbdd20aSAndroid Build Coastguard Workertype Modes = CounterOptions['yMode'];
37*6dbdd20aSAndroid Build Coastguard Worker
38*6dbdd20aSAndroid Build Coastguard Worker// Sets the default 'mode' for counter tracks. If the regex matches
39*6dbdd20aSAndroid Build Coastguard Worker// then the paired mode is used. Entries are in priority order so the
40*6dbdd20aSAndroid Build Coastguard Worker// first match wins.
41*6dbdd20aSAndroid Build Coastguard Workerconst COUNTER_REGEX: [RegExp, Modes][] = [
42*6dbdd20aSAndroid Build Coastguard Worker  // Power counters make more sense in rate mode since you're typically
43*6dbdd20aSAndroid Build Coastguard Worker  // interested in the slope of the graph rather than the absolute
44*6dbdd20aSAndroid Build Coastguard Worker  // value.
45*6dbdd20aSAndroid Build Coastguard Worker  [new RegExp('^power..*$'), 'rate'],
46*6dbdd20aSAndroid Build Coastguard Worker  // Same for cumulative PSI stall time counters, e.g., psi.cpu.some.
47*6dbdd20aSAndroid Build Coastguard Worker  [new RegExp('^psi..*$'), 'rate'],
48*6dbdd20aSAndroid Build Coastguard Worker  // Same for network counters.
49*6dbdd20aSAndroid Build Coastguard Worker  [NETWORK_TRACK_REGEX, 'rate'],
50*6dbdd20aSAndroid Build Coastguard Worker  // Entity residency
51*6dbdd20aSAndroid Build Coastguard Worker  [ENTITY_RESIDENCY_REGEX, 'rate'],
52*6dbdd20aSAndroid Build Coastguard Worker];
53*6dbdd20aSAndroid Build Coastguard Worker
54*6dbdd20aSAndroid Build Coastguard Workerfunction getCounterMode(name: string): Modes | undefined {
55*6dbdd20aSAndroid Build Coastguard Worker  for (const [re, mode] of COUNTER_REGEX) {
56*6dbdd20aSAndroid Build Coastguard Worker    if (name.match(re)) {
57*6dbdd20aSAndroid Build Coastguard Worker      return mode;
58*6dbdd20aSAndroid Build Coastguard Worker    }
59*6dbdd20aSAndroid Build Coastguard Worker  }
60*6dbdd20aSAndroid Build Coastguard Worker  return undefined;
61*6dbdd20aSAndroid Build Coastguard Worker}
62*6dbdd20aSAndroid Build Coastguard Worker
63*6dbdd20aSAndroid Build Coastguard Workerfunction getDefaultCounterOptions(name: string): Partial<CounterOptions> {
64*6dbdd20aSAndroid Build Coastguard Worker  const options: Partial<CounterOptions> = {};
65*6dbdd20aSAndroid Build Coastguard Worker  options.yMode = getCounterMode(name);
66*6dbdd20aSAndroid Build Coastguard Worker
67*6dbdd20aSAndroid Build Coastguard Worker  if (name.endsWith('_pct')) {
68*6dbdd20aSAndroid Build Coastguard Worker    options.yOverrideMinimum = 0;
69*6dbdd20aSAndroid Build Coastguard Worker    options.yOverrideMaximum = 100;
70*6dbdd20aSAndroid Build Coastguard Worker    options.unit = '%';
71*6dbdd20aSAndroid Build Coastguard Worker  }
72*6dbdd20aSAndroid Build Coastguard Worker
73*6dbdd20aSAndroid Build Coastguard Worker  if (name.startsWith('power.')) {
74*6dbdd20aSAndroid Build Coastguard Worker    options.yRangeSharingKey = 'power';
75*6dbdd20aSAndroid Build Coastguard Worker  }
76*6dbdd20aSAndroid Build Coastguard Worker
77*6dbdd20aSAndroid Build Coastguard Worker  // TODO(stevegolton): We need to rethink how this works for virtual memory.
78*6dbdd20aSAndroid Build Coastguard Worker  // The problem is we can easily have > 10GB virtual memory which dwarfs
79*6dbdd20aSAndroid Build Coastguard Worker  // physical memory making other memory tracks difficult to read.
80*6dbdd20aSAndroid Build Coastguard Worker
81*6dbdd20aSAndroid Build Coastguard Worker  // if (name.startsWith('mem.')) {
82*6dbdd20aSAndroid Build Coastguard Worker  //   options.yRangeSharingKey = 'mem';
83*6dbdd20aSAndroid Build Coastguard Worker  // }
84*6dbdd20aSAndroid Build Coastguard Worker
85*6dbdd20aSAndroid Build Coastguard Worker  // All 'Entity residency: foo bar1234' tracks should share a y-axis
86*6dbdd20aSAndroid Build Coastguard Worker  // with 'Entity residency: foo baz5678' etc tracks:
87*6dbdd20aSAndroid Build Coastguard Worker  {
88*6dbdd20aSAndroid Build Coastguard Worker    const r = new RegExp('Entity residency: ([^ ]+) ');
89*6dbdd20aSAndroid Build Coastguard Worker    const m = r.exec(name);
90*6dbdd20aSAndroid Build Coastguard Worker    if (m) {
91*6dbdd20aSAndroid Build Coastguard Worker      options.yRangeSharingKey = `entity-residency-${m[1]}`;
92*6dbdd20aSAndroid Build Coastguard Worker    }
93*6dbdd20aSAndroid Build Coastguard Worker  }
94*6dbdd20aSAndroid Build Coastguard Worker
95*6dbdd20aSAndroid Build Coastguard Worker  {
96*6dbdd20aSAndroid Build Coastguard Worker    const r = new RegExp('GPU .* Frequency');
97*6dbdd20aSAndroid Build Coastguard Worker    const m = r.exec(name);
98*6dbdd20aSAndroid Build Coastguard Worker    if (m) {
99*6dbdd20aSAndroid Build Coastguard Worker      options.yRangeSharingKey = 'gpu-frequency';
100*6dbdd20aSAndroid Build Coastguard Worker    }
101*6dbdd20aSAndroid Build Coastguard Worker  }
102*6dbdd20aSAndroid Build Coastguard Worker
103*6dbdd20aSAndroid Build Coastguard Worker  return options;
104*6dbdd20aSAndroid Build Coastguard Worker}
105*6dbdd20aSAndroid Build Coastguard Worker
106*6dbdd20aSAndroid Build Coastguard Workerexport default class implements PerfettoPlugin {
107*6dbdd20aSAndroid Build Coastguard Worker  static readonly id = 'dev.perfetto.Counter';
108*6dbdd20aSAndroid Build Coastguard Worker  static readonly dependencies = [ProcessThreadGroupsPlugin];
109*6dbdd20aSAndroid Build Coastguard Worker
110*6dbdd20aSAndroid Build Coastguard Worker  async onTraceLoad(ctx: Trace): Promise<void> {
111*6dbdd20aSAndroid Build Coastguard Worker    await this.addCounterTracks(ctx);
112*6dbdd20aSAndroid Build Coastguard Worker    await this.addGpuFrequencyTracks(ctx);
113*6dbdd20aSAndroid Build Coastguard Worker    await this.addCpuFreqLimitCounterTracks(ctx);
114*6dbdd20aSAndroid Build Coastguard Worker    await this.addCpuTimeCounterTracks(ctx);
115*6dbdd20aSAndroid Build Coastguard Worker    await this.addCpuPerfCounterTracks(ctx);
116*6dbdd20aSAndroid Build Coastguard Worker    await this.addThreadCounterTracks(ctx);
117*6dbdd20aSAndroid Build Coastguard Worker    await this.addProcessCounterTracks(ctx);
118*6dbdd20aSAndroid Build Coastguard Worker
119*6dbdd20aSAndroid Build Coastguard Worker    ctx.selection.registerAreaSelectionAggregator(
120*6dbdd20aSAndroid Build Coastguard Worker      new CounterSelectionAggregator(),
121*6dbdd20aSAndroid Build Coastguard Worker    );
122*6dbdd20aSAndroid Build Coastguard Worker  }
123*6dbdd20aSAndroid Build Coastguard Worker
124*6dbdd20aSAndroid Build Coastguard Worker  private async addCounterTracks(ctx: Trace) {
125*6dbdd20aSAndroid Build Coastguard Worker    const result = await ctx.engine.query(`
126*6dbdd20aSAndroid Build Coastguard Worker      select name, id, unit
127*6dbdd20aSAndroid Build Coastguard Worker      from (
128*6dbdd20aSAndroid Build Coastguard Worker        select name, id, unit
129*6dbdd20aSAndroid Build Coastguard Worker        from counter_track
130*6dbdd20aSAndroid Build Coastguard Worker        join _counter_track_summary using (id)
131*6dbdd20aSAndroid Build Coastguard Worker        where is_legacy_global
132*6dbdd20aSAndroid Build Coastguard Worker        union
133*6dbdd20aSAndroid Build Coastguard Worker        select name, id, unit
134*6dbdd20aSAndroid Build Coastguard Worker        from gpu_counter_track
135*6dbdd20aSAndroid Build Coastguard Worker        join _counter_track_summary using (id)
136*6dbdd20aSAndroid Build Coastguard Worker        where name != 'gpufreq'
137*6dbdd20aSAndroid Build Coastguard Worker      )
138*6dbdd20aSAndroid Build Coastguard Worker      order by name
139*6dbdd20aSAndroid Build Coastguard Worker    `);
140*6dbdd20aSAndroid Build Coastguard Worker
141*6dbdd20aSAndroid Build Coastguard Worker    // Add global or GPU counter tracks that are not bound to any pid/tid.
142*6dbdd20aSAndroid Build Coastguard Worker    const it = result.iter({
143*6dbdd20aSAndroid Build Coastguard Worker      name: STR,
144*6dbdd20aSAndroid Build Coastguard Worker      unit: STR_NULL,
145*6dbdd20aSAndroid Build Coastguard Worker      id: NUM,
146*6dbdd20aSAndroid Build Coastguard Worker    });
147*6dbdd20aSAndroid Build Coastguard Worker
148*6dbdd20aSAndroid Build Coastguard Worker    for (; it.valid(); it.next()) {
149*6dbdd20aSAndroid Build Coastguard Worker      const trackId = it.id;
150*6dbdd20aSAndroid Build Coastguard Worker      const title = it.name;
151*6dbdd20aSAndroid Build Coastguard Worker      const unit = it.unit ?? undefined;
152*6dbdd20aSAndroid Build Coastguard Worker
153*6dbdd20aSAndroid Build Coastguard Worker      const uri = `/counter_${trackId}`;
154*6dbdd20aSAndroid Build Coastguard Worker      ctx.tracks.registerTrack({
155*6dbdd20aSAndroid Build Coastguard Worker        uri,
156*6dbdd20aSAndroid Build Coastguard Worker        title,
157*6dbdd20aSAndroid Build Coastguard Worker        tags: {
158*6dbdd20aSAndroid Build Coastguard Worker          kind: COUNTER_TRACK_KIND,
159*6dbdd20aSAndroid Build Coastguard Worker          trackIds: [trackId],
160*6dbdd20aSAndroid Build Coastguard Worker        },
161*6dbdd20aSAndroid Build Coastguard Worker        track: new TraceProcessorCounterTrack(
162*6dbdd20aSAndroid Build Coastguard Worker          ctx,
163*6dbdd20aSAndroid Build Coastguard Worker          uri,
164*6dbdd20aSAndroid Build Coastguard Worker          {
165*6dbdd20aSAndroid Build Coastguard Worker            ...getDefaultCounterOptions(title),
166*6dbdd20aSAndroid Build Coastguard Worker            unit,
167*6dbdd20aSAndroid Build Coastguard Worker          },
168*6dbdd20aSAndroid Build Coastguard Worker          trackId,
169*6dbdd20aSAndroid Build Coastguard Worker          title,
170*6dbdd20aSAndroid Build Coastguard Worker        ),
171*6dbdd20aSAndroid Build Coastguard Worker      });
172*6dbdd20aSAndroid Build Coastguard Worker      const track = new TrackNode({uri, title});
173*6dbdd20aSAndroid Build Coastguard Worker      ctx.workspace.addChildInOrder(track);
174*6dbdd20aSAndroid Build Coastguard Worker    }
175*6dbdd20aSAndroid Build Coastguard Worker  }
176*6dbdd20aSAndroid Build Coastguard Worker
177*6dbdd20aSAndroid Build Coastguard Worker  async addCpuFreqLimitCounterTracks(ctx: Trace): Promise<void> {
178*6dbdd20aSAndroid Build Coastguard Worker    const cpuFreqLimitCounterTracksSql = `
179*6dbdd20aSAndroid Build Coastguard Worker      select name, id
180*6dbdd20aSAndroid Build Coastguard Worker      from cpu_counter_track
181*6dbdd20aSAndroid Build Coastguard Worker      join _counter_track_summary using (id)
182*6dbdd20aSAndroid Build Coastguard Worker      where name glob "Cpu * Freq Limit"
183*6dbdd20aSAndroid Build Coastguard Worker      order by name asc
184*6dbdd20aSAndroid Build Coastguard Worker    `;
185*6dbdd20aSAndroid Build Coastguard Worker
186*6dbdd20aSAndroid Build Coastguard Worker    this.addCpuCounterTracks(ctx, cpuFreqLimitCounterTracksSql, 'cpuFreqLimit');
187*6dbdd20aSAndroid Build Coastguard Worker  }
188*6dbdd20aSAndroid Build Coastguard Worker
189*6dbdd20aSAndroid Build Coastguard Worker  async addCpuTimeCounterTracks(ctx: Trace): Promise<void> {
190*6dbdd20aSAndroid Build Coastguard Worker    const cpuTimeCounterTracksSql = `
191*6dbdd20aSAndroid Build Coastguard Worker      select name, id
192*6dbdd20aSAndroid Build Coastguard Worker      from cpu_counter_track
193*6dbdd20aSAndroid Build Coastguard Worker      join _counter_track_summary using (id)
194*6dbdd20aSAndroid Build Coastguard Worker      where name glob "cpu.times.*"
195*6dbdd20aSAndroid Build Coastguard Worker      order by name asc
196*6dbdd20aSAndroid Build Coastguard Worker    `;
197*6dbdd20aSAndroid Build Coastguard Worker    this.addCpuCounterTracks(ctx, cpuTimeCounterTracksSql, 'cpuTime');
198*6dbdd20aSAndroid Build Coastguard Worker  }
199*6dbdd20aSAndroid Build Coastguard Worker
200*6dbdd20aSAndroid Build Coastguard Worker  async addCpuPerfCounterTracks(ctx: Trace): Promise<void> {
201*6dbdd20aSAndroid Build Coastguard Worker    // Perf counter tracks are bound to CPUs, follow the scheduling and
202*6dbdd20aSAndroid Build Coastguard Worker    // frequency track naming convention ("Cpu N ...").
203*6dbdd20aSAndroid Build Coastguard Worker    // Note: we might not have a track for a given cpu if no data was seen from
204*6dbdd20aSAndroid Build Coastguard Worker    // it. This might look surprising in the UI, but placeholder tracks are
205*6dbdd20aSAndroid Build Coastguard Worker    // wasteful as there's no way of collapsing global counter tracks at the
206*6dbdd20aSAndroid Build Coastguard Worker    // moment.
207*6dbdd20aSAndroid Build Coastguard Worker    const addCpuPerfCounterTracksSql = `
208*6dbdd20aSAndroid Build Coastguard Worker      select printf("Cpu %u %s", cpu, name) as name, id
209*6dbdd20aSAndroid Build Coastguard Worker      from perf_counter_track as pct
210*6dbdd20aSAndroid Build Coastguard Worker      join _counter_track_summary using (id)
211*6dbdd20aSAndroid Build Coastguard Worker      order by perf_session_id asc, pct.name asc, cpu asc
212*6dbdd20aSAndroid Build Coastguard Worker    `;
213*6dbdd20aSAndroid Build Coastguard Worker    this.addCpuCounterTracks(ctx, addCpuPerfCounterTracksSql, 'cpuPerf');
214*6dbdd20aSAndroid Build Coastguard Worker  }
215*6dbdd20aSAndroid Build Coastguard Worker
216*6dbdd20aSAndroid Build Coastguard Worker  async addCpuCounterTracks(
217*6dbdd20aSAndroid Build Coastguard Worker    ctx: Trace,
218*6dbdd20aSAndroid Build Coastguard Worker    sql: string,
219*6dbdd20aSAndroid Build Coastguard Worker    scope: string,
220*6dbdd20aSAndroid Build Coastguard Worker  ): Promise<void> {
221*6dbdd20aSAndroid Build Coastguard Worker    const result = await ctx.engine.query(sql);
222*6dbdd20aSAndroid Build Coastguard Worker
223*6dbdd20aSAndroid Build Coastguard Worker    const it = result.iter({
224*6dbdd20aSAndroid Build Coastguard Worker      name: STR,
225*6dbdd20aSAndroid Build Coastguard Worker      id: NUM,
226*6dbdd20aSAndroid Build Coastguard Worker    });
227*6dbdd20aSAndroid Build Coastguard Worker
228*6dbdd20aSAndroid Build Coastguard Worker    for (; it.valid(); it.next()) {
229*6dbdd20aSAndroid Build Coastguard Worker      const name = it.name;
230*6dbdd20aSAndroid Build Coastguard Worker      const trackId = it.id;
231*6dbdd20aSAndroid Build Coastguard Worker      const uri = `counter.cpu.${trackId}`;
232*6dbdd20aSAndroid Build Coastguard Worker      ctx.tracks.registerTrack({
233*6dbdd20aSAndroid Build Coastguard Worker        uri,
234*6dbdd20aSAndroid Build Coastguard Worker        title: name,
235*6dbdd20aSAndroid Build Coastguard Worker        tags: {
236*6dbdd20aSAndroid Build Coastguard Worker          kind: COUNTER_TRACK_KIND,
237*6dbdd20aSAndroid Build Coastguard Worker          trackIds: [trackId],
238*6dbdd20aSAndroid Build Coastguard Worker          scope,
239*6dbdd20aSAndroid Build Coastguard Worker        },
240*6dbdd20aSAndroid Build Coastguard Worker        track: new TraceProcessorCounterTrack(
241*6dbdd20aSAndroid Build Coastguard Worker          ctx,
242*6dbdd20aSAndroid Build Coastguard Worker          uri,
243*6dbdd20aSAndroid Build Coastguard Worker          getDefaultCounterOptions(name),
244*6dbdd20aSAndroid Build Coastguard Worker          trackId,
245*6dbdd20aSAndroid Build Coastguard Worker          name,
246*6dbdd20aSAndroid Build Coastguard Worker        ),
247*6dbdd20aSAndroid Build Coastguard Worker      });
248*6dbdd20aSAndroid Build Coastguard Worker      const trackNode = new TrackNode({uri, title: name, sortOrder: -20});
249*6dbdd20aSAndroid Build Coastguard Worker      ctx.workspace.addChildInOrder(trackNode);
250*6dbdd20aSAndroid Build Coastguard Worker    }
251*6dbdd20aSAndroid Build Coastguard Worker  }
252*6dbdd20aSAndroid Build Coastguard Worker
253*6dbdd20aSAndroid Build Coastguard Worker  async addThreadCounterTracks(ctx: Trace): Promise<void> {
254*6dbdd20aSAndroid Build Coastguard Worker    const result = await ctx.engine.query(`
255*6dbdd20aSAndroid Build Coastguard Worker      select
256*6dbdd20aSAndroid Build Coastguard Worker        thread_counter_track.name as trackName,
257*6dbdd20aSAndroid Build Coastguard Worker        utid,
258*6dbdd20aSAndroid Build Coastguard Worker        upid,
259*6dbdd20aSAndroid Build Coastguard Worker        tid,
260*6dbdd20aSAndroid Build Coastguard Worker        thread.name as threadName,
261*6dbdd20aSAndroid Build Coastguard Worker        thread_counter_track.id as trackId,
262*6dbdd20aSAndroid Build Coastguard Worker        thread.start_ts as startTs,
263*6dbdd20aSAndroid Build Coastguard Worker        thread.end_ts as endTs
264*6dbdd20aSAndroid Build Coastguard Worker      from thread_counter_track
265*6dbdd20aSAndroid Build Coastguard Worker      join _counter_track_summary using (id)
266*6dbdd20aSAndroid Build Coastguard Worker      join thread using(utid)
267*6dbdd20aSAndroid Build Coastguard Worker      where thread_counter_track.name != 'thread_time'
268*6dbdd20aSAndroid Build Coastguard Worker    `);
269*6dbdd20aSAndroid Build Coastguard Worker
270*6dbdd20aSAndroid Build Coastguard Worker    const it = result.iter({
271*6dbdd20aSAndroid Build Coastguard Worker      startTs: LONG_NULL,
272*6dbdd20aSAndroid Build Coastguard Worker      trackId: NUM,
273*6dbdd20aSAndroid Build Coastguard Worker      endTs: LONG_NULL,
274*6dbdd20aSAndroid Build Coastguard Worker      trackName: STR_NULL,
275*6dbdd20aSAndroid Build Coastguard Worker      utid: NUM,
276*6dbdd20aSAndroid Build Coastguard Worker      upid: NUM_NULL,
277*6dbdd20aSAndroid Build Coastguard Worker      tid: NUM_NULL,
278*6dbdd20aSAndroid Build Coastguard Worker      threadName: STR_NULL,
279*6dbdd20aSAndroid Build Coastguard Worker    });
280*6dbdd20aSAndroid Build Coastguard Worker    for (; it.valid(); it.next()) {
281*6dbdd20aSAndroid Build Coastguard Worker      const utid = it.utid;
282*6dbdd20aSAndroid Build Coastguard Worker      const upid = it.upid;
283*6dbdd20aSAndroid Build Coastguard Worker      const tid = it.tid;
284*6dbdd20aSAndroid Build Coastguard Worker      const trackId = it.trackId;
285*6dbdd20aSAndroid Build Coastguard Worker      const trackName = it.trackName;
286*6dbdd20aSAndroid Build Coastguard Worker      const threadName = it.threadName;
287*6dbdd20aSAndroid Build Coastguard Worker      const kind = COUNTER_TRACK_KIND;
288*6dbdd20aSAndroid Build Coastguard Worker      const name = getTrackName({
289*6dbdd20aSAndroid Build Coastguard Worker        name: trackName,
290*6dbdd20aSAndroid Build Coastguard Worker        utid,
291*6dbdd20aSAndroid Build Coastguard Worker        tid,
292*6dbdd20aSAndroid Build Coastguard Worker        kind,
293*6dbdd20aSAndroid Build Coastguard Worker        threadName,
294*6dbdd20aSAndroid Build Coastguard Worker        threadTrack: true,
295*6dbdd20aSAndroid Build Coastguard Worker      });
296*6dbdd20aSAndroid Build Coastguard Worker      const uri = `${getThreadUriPrefix(upid, utid)}_counter_${trackId}`;
297*6dbdd20aSAndroid Build Coastguard Worker      ctx.tracks.registerTrack({
298*6dbdd20aSAndroid Build Coastguard Worker        uri,
299*6dbdd20aSAndroid Build Coastguard Worker        title: name,
300*6dbdd20aSAndroid Build Coastguard Worker        tags: {
301*6dbdd20aSAndroid Build Coastguard Worker          kind,
302*6dbdd20aSAndroid Build Coastguard Worker          trackIds: [trackId],
303*6dbdd20aSAndroid Build Coastguard Worker          utid,
304*6dbdd20aSAndroid Build Coastguard Worker          upid: upid ?? undefined,
305*6dbdd20aSAndroid Build Coastguard Worker          scope: 'thread',
306*6dbdd20aSAndroid Build Coastguard Worker        },
307*6dbdd20aSAndroid Build Coastguard Worker        track: new TraceProcessorCounterTrack(
308*6dbdd20aSAndroid Build Coastguard Worker          ctx,
309*6dbdd20aSAndroid Build Coastguard Worker          uri,
310*6dbdd20aSAndroid Build Coastguard Worker          getDefaultCounterOptions(name),
311*6dbdd20aSAndroid Build Coastguard Worker          trackId,
312*6dbdd20aSAndroid Build Coastguard Worker          name,
313*6dbdd20aSAndroid Build Coastguard Worker        ),
314*6dbdd20aSAndroid Build Coastguard Worker      });
315*6dbdd20aSAndroid Build Coastguard Worker      const group = ctx.plugins
316*6dbdd20aSAndroid Build Coastguard Worker        .getPlugin(ProcessThreadGroupsPlugin)
317*6dbdd20aSAndroid Build Coastguard Worker        .getGroupForThread(utid);
318*6dbdd20aSAndroid Build Coastguard Worker      const track = new TrackNode({uri, title: name, sortOrder: 30});
319*6dbdd20aSAndroid Build Coastguard Worker      group?.addChildInOrder(track);
320*6dbdd20aSAndroid Build Coastguard Worker    }
321*6dbdd20aSAndroid Build Coastguard Worker  }
322*6dbdd20aSAndroid Build Coastguard Worker
323*6dbdd20aSAndroid Build Coastguard Worker  async addProcessCounterTracks(ctx: Trace): Promise<void> {
324*6dbdd20aSAndroid Build Coastguard Worker    const result = await ctx.engine.query(`
325*6dbdd20aSAndroid Build Coastguard Worker      select
326*6dbdd20aSAndroid Build Coastguard Worker        process_counter_track.id as trackId,
327*6dbdd20aSAndroid Build Coastguard Worker        process_counter_track.name as trackName,
328*6dbdd20aSAndroid Build Coastguard Worker        upid,
329*6dbdd20aSAndroid Build Coastguard Worker        process.pid,
330*6dbdd20aSAndroid Build Coastguard Worker        process.name as processName
331*6dbdd20aSAndroid Build Coastguard Worker      from process_counter_track
332*6dbdd20aSAndroid Build Coastguard Worker      join _counter_track_summary using (id)
333*6dbdd20aSAndroid Build Coastguard Worker      join process using(upid)
334*6dbdd20aSAndroid Build Coastguard Worker      order by trackName;
335*6dbdd20aSAndroid Build Coastguard Worker    `);
336*6dbdd20aSAndroid Build Coastguard Worker    const it = result.iter({
337*6dbdd20aSAndroid Build Coastguard Worker      trackId: NUM,
338*6dbdd20aSAndroid Build Coastguard Worker      trackName: STR_NULL,
339*6dbdd20aSAndroid Build Coastguard Worker      upid: NUM,
340*6dbdd20aSAndroid Build Coastguard Worker      pid: NUM_NULL,
341*6dbdd20aSAndroid Build Coastguard Worker      processName: STR_NULL,
342*6dbdd20aSAndroid Build Coastguard Worker    });
343*6dbdd20aSAndroid Build Coastguard Worker    for (let i = 0; it.valid(); ++i, it.next()) {
344*6dbdd20aSAndroid Build Coastguard Worker      const trackId = it.trackId;
345*6dbdd20aSAndroid Build Coastguard Worker      const pid = it.pid;
346*6dbdd20aSAndroid Build Coastguard Worker      const trackName = it.trackName;
347*6dbdd20aSAndroid Build Coastguard Worker      const upid = it.upid;
348*6dbdd20aSAndroid Build Coastguard Worker      const processName = it.processName;
349*6dbdd20aSAndroid Build Coastguard Worker      const kind = COUNTER_TRACK_KIND;
350*6dbdd20aSAndroid Build Coastguard Worker      const name = getTrackName({
351*6dbdd20aSAndroid Build Coastguard Worker        name: trackName,
352*6dbdd20aSAndroid Build Coastguard Worker        upid,
353*6dbdd20aSAndroid Build Coastguard Worker        pid,
354*6dbdd20aSAndroid Build Coastguard Worker        kind,
355*6dbdd20aSAndroid Build Coastguard Worker        processName,
356*6dbdd20aSAndroid Build Coastguard Worker        ...(exists(trackName) && {trackName}),
357*6dbdd20aSAndroid Build Coastguard Worker      });
358*6dbdd20aSAndroid Build Coastguard Worker      const uri = `/process_${upid}/counter_${trackId}`;
359*6dbdd20aSAndroid Build Coastguard Worker      ctx.tracks.registerTrack({
360*6dbdd20aSAndroid Build Coastguard Worker        uri,
361*6dbdd20aSAndroid Build Coastguard Worker        title: name,
362*6dbdd20aSAndroid Build Coastguard Worker        tags: {
363*6dbdd20aSAndroid Build Coastguard Worker          kind,
364*6dbdd20aSAndroid Build Coastguard Worker          trackIds: [trackId],
365*6dbdd20aSAndroid Build Coastguard Worker          upid,
366*6dbdd20aSAndroid Build Coastguard Worker          scope: 'process',
367*6dbdd20aSAndroid Build Coastguard Worker        },
368*6dbdd20aSAndroid Build Coastguard Worker        track: new TraceProcessorCounterTrack(
369*6dbdd20aSAndroid Build Coastguard Worker          ctx,
370*6dbdd20aSAndroid Build Coastguard Worker          uri,
371*6dbdd20aSAndroid Build Coastguard Worker          getDefaultCounterOptions(name),
372*6dbdd20aSAndroid Build Coastguard Worker          trackId,
373*6dbdd20aSAndroid Build Coastguard Worker          name,
374*6dbdd20aSAndroid Build Coastguard Worker        ),
375*6dbdd20aSAndroid Build Coastguard Worker      });
376*6dbdd20aSAndroid Build Coastguard Worker      const group = ctx.plugins
377*6dbdd20aSAndroid Build Coastguard Worker        .getPlugin(ProcessThreadGroupsPlugin)
378*6dbdd20aSAndroid Build Coastguard Worker        .getGroupForProcess(upid);
379*6dbdd20aSAndroid Build Coastguard Worker      const track = new TrackNode({uri, title: name, sortOrder: 20});
380*6dbdd20aSAndroid Build Coastguard Worker      group?.addChildInOrder(track);
381*6dbdd20aSAndroid Build Coastguard Worker    }
382*6dbdd20aSAndroid Build Coastguard Worker  }
383*6dbdd20aSAndroid Build Coastguard Worker
384*6dbdd20aSAndroid Build Coastguard Worker  private async addGpuFrequencyTracks(ctx: Trace) {
385*6dbdd20aSAndroid Build Coastguard Worker    const engine = ctx.engine;
386*6dbdd20aSAndroid Build Coastguard Worker
387*6dbdd20aSAndroid Build Coastguard Worker    const result = await engine.query(`
388*6dbdd20aSAndroid Build Coastguard Worker      select id, gpu_id as gpuId
389*6dbdd20aSAndroid Build Coastguard Worker      from gpu_counter_track
390*6dbdd20aSAndroid Build Coastguard Worker      join _counter_track_summary using (id)
391*6dbdd20aSAndroid Build Coastguard Worker      where name = 'gpufreq'
392*6dbdd20aSAndroid Build Coastguard Worker    `);
393*6dbdd20aSAndroid Build Coastguard Worker    const it = result.iter({id: NUM, gpuId: NUM});
394*6dbdd20aSAndroid Build Coastguard Worker    for (; it.valid(); it.next()) {
395*6dbdd20aSAndroid Build Coastguard Worker      const uri = `/gpu_frequency_${it.gpuId}`;
396*6dbdd20aSAndroid Build Coastguard Worker      const name = `Gpu ${it.gpuId} Frequency`;
397*6dbdd20aSAndroid Build Coastguard Worker      ctx.tracks.registerTrack({
398*6dbdd20aSAndroid Build Coastguard Worker        uri,
399*6dbdd20aSAndroid Build Coastguard Worker        title: name,
400*6dbdd20aSAndroid Build Coastguard Worker        tags: {
401*6dbdd20aSAndroid Build Coastguard Worker          kind: COUNTER_TRACK_KIND,
402*6dbdd20aSAndroid Build Coastguard Worker          trackIds: [it.id],
403*6dbdd20aSAndroid Build Coastguard Worker          scope: 'gpuFreq',
404*6dbdd20aSAndroid Build Coastguard Worker        },
405*6dbdd20aSAndroid Build Coastguard Worker        track: new TraceProcessorCounterTrack(
406*6dbdd20aSAndroid Build Coastguard Worker          ctx,
407*6dbdd20aSAndroid Build Coastguard Worker          uri,
408*6dbdd20aSAndroid Build Coastguard Worker          getDefaultCounterOptions(name),
409*6dbdd20aSAndroid Build Coastguard Worker          it.id,
410*6dbdd20aSAndroid Build Coastguard Worker          name,
411*6dbdd20aSAndroid Build Coastguard Worker        ),
412*6dbdd20aSAndroid Build Coastguard Worker      });
413*6dbdd20aSAndroid Build Coastguard Worker      const track = new TrackNode({uri, title: name, sortOrder: -20});
414*6dbdd20aSAndroid Build Coastguard Worker      ctx.workspace.addChildInOrder(track);
415*6dbdd20aSAndroid Build Coastguard Worker    }
416*6dbdd20aSAndroid Build Coastguard Worker  }
417*6dbdd20aSAndroid Build Coastguard Worker}
418