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'; 25 26function uriForSchedTrack(cpu: number): string { 27 return `/sched_cpu${cpu}`; 28} 29 30export default class implements PerfettoPlugin { 31 static readonly id = 'dev.perfetto.CpuSlices'; 32 static readonly dependencies = [ThreadPlugin]; 33 34 async onTraceLoad(ctx: Trace): Promise<void> { 35 ctx.selection.registerAreaSelectionAggregator( 36 new CpuSliceSelectionAggregator(), 37 ); 38 ctx.selection.registerAreaSelectionAggregator( 39 new CpuSliceByProcessSelectionAggregator(), 40 ); 41 42 const cpus = ctx.traceInfo.cpus; 43 const cpuToClusterType = await this.getAndroidCpuClusterTypes(ctx.engine); 44 45 for (const cpu of cpus) { 46 const size = cpuToClusterType.get(cpu); 47 const uri = uriForSchedTrack(cpu); 48 49 const threads = ctx.plugins.getPlugin(ThreadPlugin).getThreadMap(); 50 51 const name = size === undefined ? `Cpu ${cpu}` : `Cpu ${cpu} (${size})`; 52 ctx.tracks.registerTrack({ 53 uri, 54 title: name, 55 tags: { 56 kind: CPU_SLICE_TRACK_KIND, 57 cpu, 58 }, 59 track: new CpuSliceTrack(ctx, uri, cpu, threads), 60 }); 61 const trackNode = new TrackNode({uri, title: name, sortOrder: -50}); 62 ctx.workspace.addChildInOrder(trackNode); 63 } 64 65 ctx.selection.registerSqlSelectionResolver({ 66 sqlTableName: 'sched_slice', 67 callback: async (id: number) => { 68 const result = await ctx.engine.query(` 69 select 70 cpu 71 from sched_slice 72 where id = ${id} 73 `); 74 75 const cpu = result.firstRow({ 76 cpu: NUM, 77 }).cpu; 78 79 return { 80 eventId: id, 81 trackUri: uriForSchedTrack(cpu), 82 }; 83 }, 84 }); 85 } 86 87 async getAndroidCpuClusterTypes( 88 engine: Engine, 89 ): Promise<Map<number, string>> { 90 const cpuToClusterType = new Map<number, string>(); 91 await engine.query(` 92 include perfetto module android.cpu.cluster_type; 93 `); 94 const result = await engine.query(` 95 select cpu, cluster_type as clusterType 96 from android_cpu_cluster_mapping 97 `); 98 99 const it = result.iter({ 100 cpu: NUM, 101 clusterType: STR_NULL, 102 }); 103 104 for (; it.valid(); it.next()) { 105 const clusterType = it.clusterType; 106 if (clusterType !== null) { 107 cpuToClusterType.set(it.cpu, clusterType); 108 } 109 } 110 111 return cpuToClusterType; 112 } 113} 114