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 {CPU_SLICE_TRACK_KIND} from '../../public/track_kinds'; 16import {Engine} from '../../trace_processor/engine'; 17import {Trace} from '../../public/trace'; 18import {PerfettoPlugin} from '../../public/plugin'; 19import {NUM, STR_NULL} from '../../trace_processor/query_result'; 20import {CpuSliceTrack} from './cpu_slice_track'; 21import {TrackNode} from '../../public/workspace'; 22import {CpuSliceSelectionAggregator} from './cpu_slice_selection_aggregator'; 23import {CpuSliceByProcessSelectionAggregator} from './cpu_slice_by_process_selection_aggregator'; 24import ThreadPlugin from '../dev.perfetto.Thread'; 25import {createAggregationToTabAdaptor} from '../../components/aggregation_adapter'; 26 27function uriForSchedTrack(cpu: number): string { 28 return `/sched_cpu${cpu}`; 29} 30 31export default class implements PerfettoPlugin { 32 static readonly id = 'dev.perfetto.CpuSlices'; 33 static readonly dependencies = [ThreadPlugin]; 34 35 async onTraceLoad(ctx: Trace): Promise<void> { 36 ctx.selection.registerAreaSelectionTab( 37 createAggregationToTabAdaptor(ctx, new CpuSliceSelectionAggregator()), 38 ); 39 ctx.selection.registerAreaSelectionTab( 40 createAggregationToTabAdaptor( 41 ctx, 42 new CpuSliceByProcessSelectionAggregator(), 43 ), 44 ); 45 46 // ctx.traceInfo.cpus contains all cpus seen from all events. Filter the set 47 // if it's seen in sched slices. 48 const queryRes = await ctx.engine.query( 49 `select distinct ucpu from sched order by ucpu;`, 50 ); 51 const ucpus = new Set<number>(); 52 for (const it = queryRes.iter({ucpu: NUM}); it.valid(); it.next()) { 53 ucpus.add(it.ucpu); 54 } 55 const cpus = ctx.traceInfo.cpus.filter((cpu) => ucpus.has(cpu.ucpu)); 56 const cpuToClusterType = await this.getAndroidCpuClusterTypes(ctx.engine); 57 58 for (const cpu of cpus) { 59 const uri = uriForSchedTrack(cpu.ucpu); 60 const size = cpuToClusterType.get(cpu.cpu); 61 const sizeStr = size === undefined ? `` : ` (${size})`; 62 const name = `Cpu ${cpu.cpu}${sizeStr}${cpu.maybeMachineLabel()}`; 63 64 const threads = ctx.plugins.getPlugin(ThreadPlugin).getThreadMap(); 65 66 ctx.tracks.registerTrack({ 67 uri, 68 title: name, 69 tags: { 70 kind: CPU_SLICE_TRACK_KIND, 71 cpu: cpu.ucpu, 72 }, 73 track: new CpuSliceTrack(ctx, uri, cpu, threads), 74 }); 75 const trackNode = new TrackNode({uri, title: name, sortOrder: -50}); 76 ctx.workspace.addChildInOrder(trackNode); 77 } 78 } 79 80 async getAndroidCpuClusterTypes( 81 engine: Engine, 82 ): Promise<Map<number, string>> { 83 const cpuToClusterType = new Map<number, string>(); 84 await engine.query(` 85 include perfetto module android.cpu.cluster_type; 86 `); 87 const result = await engine.query(` 88 select cpu, cluster_type as clusterType 89 from android_cpu_cluster_mapping 90 `); 91 92 const it = result.iter({ 93 cpu: NUM, 94 clusterType: STR_NULL, 95 }); 96 97 for (; it.valid(); it.next()) { 98 const clusterType = it.clusterType; 99 if (clusterType !== null) { 100 cpuToClusterType.set(it.cpu, clusterType); 101 } 102 } 103 104 return cpuToClusterType; 105 } 106} 107