blob: a48f2c6b2ebd614216fa119162184957da742f2d [file] [edit]
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import m from 'mithril';
import {PerfettoPlugin} from '../../public/plugin';
import {Trace} from '../../public/trace';
import {CPU_FREQ_TRACK_KIND} from '../../public/track_kinds';
import {TrackNode} from '../../public/workspace';
import {NUM, NUM_NULL} from '../../trace_processor/query_result';
import {CpuFreqTrack} from './cpu_freq_track';
import {Anchor} from '../../widgets/anchor';
import {Icons} from '../../base/semantic_icons';
export default class implements PerfettoPlugin {
static readonly id = 'dev.perfetto.CpuFreq';
async onTraceLoad(ctx: Trace): Promise<void> {
const {engine} = ctx;
// ctx.traceInfo.cpus contains all cpus seen from all events. Filter the set
// if it's seen in cpu_counter_track.
const queryRes = await ctx.engine.query(
`select distinct cpu, ifnull(machine_id, 0) as machine
from cpu_counter_track`,
);
const cpuAndMachine = new Set<string>();
for (
const it = queryRes.iter({cpu: NUM, machine: NUM});
it.valid();
it.next()
) {
cpuAndMachine.add([it.cpu, it.machine].toString());
}
const cpus = ctx.traceInfo.cpus.filter((cpu) =>
cpuAndMachine.has([cpu.cpu, cpu.machine].toString()),
);
const maxCpuFreqResult = await engine.query(`
select ifnull(max(value), 0) as freq
from counter c
join cpu_counter_track t on c.track_id = t.id
join _counter_track_summary s on t.id = s.id
where t.type = 'cpu_frequency';
`);
const maxCpuFreq = maxCpuFreqResult.firstRow({freq: NUM}).freq;
const group = new TrackNode({
name: 'CPU Frequency',
sortOrder: -40,
isSummary: true,
collapsed: false,
});
for (const cpu of cpus) {
// Only add a cpu freq track if we have cpu freq data.
const cpuFreqIdleResult = await engine.query(`
select
id as cpuFreqId,
(
select id
from cpu_counter_track t
where t.type = 'cpu_idle'
and t.cpu = ${cpu.cpu} and ifnull(t.machine_id, 0) = ${cpu.machine}
limit 1
) as cpuIdleId
from cpu_counter_track t
join _counter_track_summary using (id)
where t.type = 'cpu_frequency'
and t.cpu = ${cpu.cpu} and ifnull(t.machine_id, 0) = ${cpu.machine}
limit 1;
`);
if (cpuFreqIdleResult.numRows() > 0) {
const row = cpuFreqIdleResult.firstRow({
cpuFreqId: NUM,
cpuIdleId: NUM_NULL,
});
const freqTrackId = row.cpuFreqId;
const idleTrackId = row.cpuIdleId === null ? undefined : row.cpuIdleId;
const config = {
// Coloring based Cpu number, same for all machines.
cpu: cpu.cpu,
maximumValue: maxCpuFreq,
freqTrackId,
idleTrackId,
};
const uri = `/cpu_freq_cpu${cpu.ucpu}`;
ctx.tracks.registerTrack({
uri,
tags: {
kind: CPU_FREQ_TRACK_KIND,
cpu: cpu.ucpu,
},
renderer: new CpuFreqTrack(config, ctx),
description: () => {
return m('', [
`Shows the CPU frequency ${cpu.toString()} over time.`,
m('br'),
m(
Anchor,
{
href: 'https://perfetto.dev/docs/data-sources/cpu-freq',
target: '_blank',
icon: Icons.ExternalLink,
},
'Documentation',
),
]);
},
});
const trackNode = new TrackNode({
uri,
name: `CPU ${cpu.toString()} Frequency`,
});
group.addChildInOrder(trackNode);
}
}
if (group.children.length > 0) {
ctx.workspace.addChildInOrder(group);
}
}
}