1// Copyright (C) 2023 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 {Trace} from '../../public/trace'; 16import {PerfettoPlugin} from '../../public/plugin'; 17import {addDebugSliceTrack} from '../../components/tracks/debug_tracks'; 18import {addQueryResultsTab} from '../../components/query_table/query_result_tab'; 19 20const PERF_TRACE_COUNTERS_PRECONDITION = ` 21 SELECT 22 str_value 23 FROM metadata 24 WHERE 25 name = 'trace_config_pbtxt' 26 AND str_value GLOB '*ftrace_events: "perf_trace_counters/sched_switch_with_ctrs"*' 27`; 28 29export default class implements PerfettoPlugin { 30 static readonly id = 'dev.perfetto.AndroidPerfTraceCounters'; 31 async onTraceLoad(ctx: Trace): Promise<void> { 32 const resp = await ctx.engine.query(PERF_TRACE_COUNTERS_PRECONDITION); 33 if (resp.numRows() === 0) return; 34 ctx.commands.registerCommand({ 35 id: 'dev.perfetto.AndroidPerfTraceCounters#ThreadRuntimeIPC', 36 name: 'Add a track to show a thread runtime ipc', 37 callback: async (tid) => { 38 if (tid === undefined) { 39 tid = prompt('Enter a thread tid', ''); 40 if (tid === null) return; 41 } 42 const sqlPrefix = ` 43 WITH 44 sched_switch_ipc AS ( 45 SELECT 46 ts, 47 EXTRACT_ARG(arg_set_id, 'prev_pid') AS tid, 48 EXTRACT_ARG(arg_set_id, 'prev_comm') AS thread_name, 49 EXTRACT_ARG(arg_set_id, 'inst') / (EXTRACT_ARG(arg_set_id, 'cyc') * 1.0) AS ipc, 50 EXTRACT_ARG(arg_set_id, 'inst') AS instruction, 51 EXTRACT_ARG(arg_set_id, 'cyc') AS cycle, 52 EXTRACT_ARG(arg_set_id, 'stallbm') AS stall_backend_mem, 53 EXTRACT_ARG(arg_set_id, 'l3dm') AS l3_cache_miss 54 FROM ftrace_event 55 WHERE name = 'sched_switch_with_ctrs' AND tid = ${tid} 56 ), 57 target_thread_sched_slice AS ( 58 SELECT s.*, t.tid, t.name FROM sched s LEFT JOIN thread t USING (utid) 59 WHERE t.tid = ${tid} 60 ), 61 target_thread_ipc_slice AS ( 62 SELECT 63 ( 64 SELECT 65 ts 66 FROM target_thread_sched_slice ts 67 WHERE ts.tid = ssi.tid AND ts.ts < ssi.ts 68 ORDER BY ts.ts DESC 69 LIMIT 1 70 ) AS ts, 71 ( 72 SELECT 73 dur 74 FROM target_thread_sched_slice ts 75 WHERE ts.tid = ssi.tid AND ts.ts < ssi.ts 76 ORDER BY ts.ts DESC 77 LIMIT 1 78 ) AS dur, 79 ssi.ipc, 80 ssi.instruction, 81 ssi.cycle, 82 ssi.stall_backend_mem, 83 ssi.l3_cache_miss 84 FROM sched_switch_ipc ssi 85 ) 86 `; 87 88 await addDebugSliceTrack({ 89 trace: ctx, 90 data: { 91 sqlSource: 92 sqlPrefix + 93 ` 94 SELECT * FROM target_thread_ipc_slice WHERE ts IS NOT NULL`, 95 }, 96 title: 'Rutime IPC:' + tid, 97 columns: {ts: 'ts', dur: 'dur', name: 'ipc'}, 98 argColumns: [ 99 'instruction', 100 'cycle', 101 'stall_backend_mem', 102 'l3_cache_miss', 103 ], 104 }); 105 addQueryResultsTab(ctx, { 106 query: 107 sqlPrefix + 108 ` 109 SELECT 110 (sum(instruction) * 1.0 / sum(cycle)*1.0) AS avg_ipc, 111 sum(dur)/1e6 as total_runtime_ms, 112 sum(instruction) AS total_instructions, 113 sum(cycle) AS total_cycles, 114 sum(stall_backend_mem) as total_stall_backend_mem, 115 sum(l3_cache_miss) as total_l3_cache_miss 116 FROM target_thread_ipc_slice WHERE ts IS NOT NULL`, 117 title: 'target thread ipc statistic', 118 }); 119 }, 120 }); 121 } 122} 123