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