• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2021 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 {PerfettoPlugin} from '../../public/plugin';
16import {Trace} from '../../public/trace';
17import {CPU_FREQ_TRACK_KIND} from '../../public/track_kinds';
18import {TrackNode} from '../../public/workspace';
19import {NUM, NUM_NULL} from '../../trace_processor/query_result';
20import {CpuFreqTrack} from './cpu_freq_track';
21
22export default class implements PerfettoPlugin {
23  static readonly id = 'dev.perfetto.CpuFreq';
24  async onTraceLoad(ctx: Trace): Promise<void> {
25    const {engine} = ctx;
26
27    // ctx.traceInfo.cpus contains all cpus seen from all events. Filter the set
28    // if it's seen in cpu_counter_track.
29    const queryRes = await ctx.engine.query(
30      `select distinct cpu, ifnull(machine_id, 0) as machine
31       from cpu_counter_track`,
32    );
33    const cpuAndMachine = new Set<string>();
34    for (
35      const it = queryRes.iter({cpu: NUM, machine: NUM});
36      it.valid();
37      it.next()
38    ) {
39      cpuAndMachine.add([it.cpu, it.machine].toString());
40    }
41    const cpus = ctx.traceInfo.cpus.filter((cpu) =>
42      cpuAndMachine.has([cpu.cpu, cpu.machine].toString()),
43    );
44
45    const maxCpuFreqResult = await engine.query(`
46      select ifnull(max(value), 0) as freq
47      from counter c
48      join cpu_counter_track t on c.track_id = t.id
49      join _counter_track_summary s on t.id = s.id
50      where t.type = 'cpu_frequency';
51    `);
52    const maxCpuFreq = maxCpuFreqResult.firstRow({freq: NUM}).freq;
53
54    for (const cpu of cpus) {
55      // Only add a cpu freq track if we have cpu freq data.
56      const cpuFreqIdleResult = await engine.query(`
57        select
58          id as cpuFreqId,
59          (
60            select id
61            from cpu_counter_track t
62            where t.type = 'cpu_idle'
63            and t.cpu = ${cpu.cpu} and ifnull(t.machine_id, 0) = ${cpu.machine}
64            limit 1
65          ) as cpuIdleId
66        from cpu_counter_track t
67        join _counter_track_summary using (id)
68        where t.type = 'cpu_frequency'
69        and t.cpu = ${cpu.cpu} and ifnull(t.machine_id, 0) = ${cpu.machine}
70        limit 1;
71      `);
72
73      if (cpuFreqIdleResult.numRows() > 0) {
74        const row = cpuFreqIdleResult.firstRow({
75          cpuFreqId: NUM,
76          cpuIdleId: NUM_NULL,
77        });
78        const freqTrackId = row.cpuFreqId;
79        const idleTrackId = row.cpuIdleId === null ? undefined : row.cpuIdleId;
80
81        const config = {
82          // Coloring based Cpu number, same for all machines.
83          cpu: cpu.cpu,
84          maximumValue: maxCpuFreq,
85          freqTrackId,
86          idleTrackId,
87        };
88
89        const uri = `/cpu_freq_cpu${cpu.ucpu}`;
90        const title = `Cpu ${cpu.toString()} Frequency`;
91        ctx.tracks.registerTrack({
92          uri,
93          title,
94          tags: {
95            kind: CPU_FREQ_TRACK_KIND,
96            cpu: cpu.ucpu,
97          },
98          track: new CpuFreqTrack(config, ctx),
99        });
100        const trackNode = new TrackNode({uri, title, sortOrder: -40});
101        ctx.workspace.addChildInOrder(trackNode);
102      }
103    }
104  }
105}
106