1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2021 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport {Trace} from '../../public/trace'; 16*6dbdd20aSAndroid Build Coastguard Workerimport {PerfettoPlugin} from '../../public/plugin'; 17*6dbdd20aSAndroid Build Coastguard Workerimport {getThreadOrProcUri} from '../../public/utils'; 18*6dbdd20aSAndroid Build Coastguard Workerimport {NUM, NUM_NULL, STR} from '../../trace_processor/query_result'; 19*6dbdd20aSAndroid Build Coastguard Workerimport { 20*6dbdd20aSAndroid Build Coastguard Worker Config as ProcessSchedulingTrackConfig, 21*6dbdd20aSAndroid Build Coastguard Worker PROCESS_SCHEDULING_TRACK_KIND, 22*6dbdd20aSAndroid Build Coastguard Worker ProcessSchedulingTrack, 23*6dbdd20aSAndroid Build Coastguard Worker} from './process_scheduling_track'; 24*6dbdd20aSAndroid Build Coastguard Workerimport { 25*6dbdd20aSAndroid Build Coastguard Worker Config as ProcessSummaryTrackConfig, 26*6dbdd20aSAndroid Build Coastguard Worker PROCESS_SUMMARY_TRACK, 27*6dbdd20aSAndroid Build Coastguard Worker ProcessSummaryTrack, 28*6dbdd20aSAndroid Build Coastguard Worker} from './process_summary_track'; 29*6dbdd20aSAndroid Build Coastguard Workerimport ThreadPlugin from '../dev.perfetto.Thread'; 30*6dbdd20aSAndroid Build Coastguard Worker 31*6dbdd20aSAndroid Build Coastguard Worker// This plugin is responsible for adding summary tracks for process and thread 32*6dbdd20aSAndroid Build Coastguard Worker// groups. 33*6dbdd20aSAndroid Build Coastguard Workerexport default class implements PerfettoPlugin { 34*6dbdd20aSAndroid Build Coastguard Worker static readonly id = 'dev.perfetto.ProcessSummary'; 35*6dbdd20aSAndroid Build Coastguard Worker static readonly dependencies = [ThreadPlugin]; 36*6dbdd20aSAndroid Build Coastguard Worker 37*6dbdd20aSAndroid Build Coastguard Worker async onTraceLoad(ctx: Trace): Promise<void> { 38*6dbdd20aSAndroid Build Coastguard Worker await this.addProcessTrackGroups(ctx); 39*6dbdd20aSAndroid Build Coastguard Worker await this.addKernelThreadSummary(ctx); 40*6dbdd20aSAndroid Build Coastguard Worker } 41*6dbdd20aSAndroid Build Coastguard Worker 42*6dbdd20aSAndroid Build Coastguard Worker private async addProcessTrackGroups(ctx: Trace): Promise<void> { 43*6dbdd20aSAndroid Build Coastguard Worker const threads = ctx.plugins.getPlugin(ThreadPlugin).getThreadMap(); 44*6dbdd20aSAndroid Build Coastguard Worker 45*6dbdd20aSAndroid Build Coastguard Worker const cpuCount = Math.max(...ctx.traceInfo.cpus, -1) + 1; 46*6dbdd20aSAndroid Build Coastguard Worker 47*6dbdd20aSAndroid Build Coastguard Worker const result = await ctx.engine.query(` 48*6dbdd20aSAndroid Build Coastguard Worker INCLUDE PERFETTO MODULE android.process_metadata; 49*6dbdd20aSAndroid Build Coastguard Worker 50*6dbdd20aSAndroid Build Coastguard Worker select * 51*6dbdd20aSAndroid Build Coastguard Worker from ( 52*6dbdd20aSAndroid Build Coastguard Worker select 53*6dbdd20aSAndroid Build Coastguard Worker _process_available_info_summary.upid, 54*6dbdd20aSAndroid Build Coastguard Worker null as utid, 55*6dbdd20aSAndroid Build Coastguard Worker process.pid, 56*6dbdd20aSAndroid Build Coastguard Worker null as tid, 57*6dbdd20aSAndroid Build Coastguard Worker process.name as processName, 58*6dbdd20aSAndroid Build Coastguard Worker null as threadName, 59*6dbdd20aSAndroid Build Coastguard Worker sum_running_dur > 0 as hasSched, 60*6dbdd20aSAndroid Build Coastguard Worker android_process_metadata.debuggable as isDebuggable, 61*6dbdd20aSAndroid Build Coastguard Worker ifnull(( 62*6dbdd20aSAndroid Build Coastguard Worker select group_concat(string_value) 63*6dbdd20aSAndroid Build Coastguard Worker from args 64*6dbdd20aSAndroid Build Coastguard Worker where 65*6dbdd20aSAndroid Build Coastguard Worker process.arg_set_id is not null and 66*6dbdd20aSAndroid Build Coastguard Worker arg_set_id = process.arg_set_id and 67*6dbdd20aSAndroid Build Coastguard Worker flat_key = 'chrome.process_label' 68*6dbdd20aSAndroid Build Coastguard Worker ), '') as chromeProcessLabels 69*6dbdd20aSAndroid Build Coastguard Worker from _process_available_info_summary 70*6dbdd20aSAndroid Build Coastguard Worker join process using(upid) 71*6dbdd20aSAndroid Build Coastguard Worker left join android_process_metadata using(upid) 72*6dbdd20aSAndroid Build Coastguard Worker ) 73*6dbdd20aSAndroid Build Coastguard Worker union all 74*6dbdd20aSAndroid Build Coastguard Worker select * 75*6dbdd20aSAndroid Build Coastguard Worker from ( 76*6dbdd20aSAndroid Build Coastguard Worker select 77*6dbdd20aSAndroid Build Coastguard Worker null, 78*6dbdd20aSAndroid Build Coastguard Worker utid, 79*6dbdd20aSAndroid Build Coastguard Worker null as pid, 80*6dbdd20aSAndroid Build Coastguard Worker tid, 81*6dbdd20aSAndroid Build Coastguard Worker null as processName, 82*6dbdd20aSAndroid Build Coastguard Worker thread.name threadName, 83*6dbdd20aSAndroid Build Coastguard Worker sum_running_dur > 0 as hasSched, 84*6dbdd20aSAndroid Build Coastguard Worker 0 as isDebuggable, 85*6dbdd20aSAndroid Build Coastguard Worker '' as chromeProcessLabels 86*6dbdd20aSAndroid Build Coastguard Worker from _thread_available_info_summary 87*6dbdd20aSAndroid Build Coastguard Worker join thread using (utid) 88*6dbdd20aSAndroid Build Coastguard Worker where upid is null 89*6dbdd20aSAndroid Build Coastguard Worker ) 90*6dbdd20aSAndroid Build Coastguard Worker `); 91*6dbdd20aSAndroid Build Coastguard Worker 92*6dbdd20aSAndroid Build Coastguard Worker const it = result.iter({ 93*6dbdd20aSAndroid Build Coastguard Worker upid: NUM_NULL, 94*6dbdd20aSAndroid Build Coastguard Worker utid: NUM_NULL, 95*6dbdd20aSAndroid Build Coastguard Worker pid: NUM_NULL, 96*6dbdd20aSAndroid Build Coastguard Worker tid: NUM_NULL, 97*6dbdd20aSAndroid Build Coastguard Worker hasSched: NUM_NULL, 98*6dbdd20aSAndroid Build Coastguard Worker isDebuggable: NUM_NULL, 99*6dbdd20aSAndroid Build Coastguard Worker chromeProcessLabels: STR, 100*6dbdd20aSAndroid Build Coastguard Worker }); 101*6dbdd20aSAndroid Build Coastguard Worker for (; it.valid(); it.next()) { 102*6dbdd20aSAndroid Build Coastguard Worker const upid = it.upid; 103*6dbdd20aSAndroid Build Coastguard Worker const utid = it.utid; 104*6dbdd20aSAndroid Build Coastguard Worker const pid = it.pid; 105*6dbdd20aSAndroid Build Coastguard Worker const tid = it.tid; 106*6dbdd20aSAndroid Build Coastguard Worker const hasSched = Boolean(it.hasSched); 107*6dbdd20aSAndroid Build Coastguard Worker const isDebuggable = Boolean(it.isDebuggable); 108*6dbdd20aSAndroid Build Coastguard Worker const subtitle = it.chromeProcessLabels; 109*6dbdd20aSAndroid Build Coastguard Worker 110*6dbdd20aSAndroid Build Coastguard Worker // Group by upid if present else by utid. 111*6dbdd20aSAndroid Build Coastguard Worker const pidForColor = pid ?? tid ?? upid ?? utid ?? 0; 112*6dbdd20aSAndroid Build Coastguard Worker const uri = getThreadOrProcUri(upid, utid); 113*6dbdd20aSAndroid Build Coastguard Worker 114*6dbdd20aSAndroid Build Coastguard Worker const chips: string[] = []; 115*6dbdd20aSAndroid Build Coastguard Worker isDebuggable && chips.push('debuggable'); 116*6dbdd20aSAndroid Build Coastguard Worker 117*6dbdd20aSAndroid Build Coastguard Worker if (hasSched) { 118*6dbdd20aSAndroid Build Coastguard Worker const config: ProcessSchedulingTrackConfig = { 119*6dbdd20aSAndroid Build Coastguard Worker pidForColor, 120*6dbdd20aSAndroid Build Coastguard Worker upid, 121*6dbdd20aSAndroid Build Coastguard Worker utid, 122*6dbdd20aSAndroid Build Coastguard Worker }; 123*6dbdd20aSAndroid Build Coastguard Worker 124*6dbdd20aSAndroid Build Coastguard Worker ctx.tracks.registerTrack({ 125*6dbdd20aSAndroid Build Coastguard Worker uri, 126*6dbdd20aSAndroid Build Coastguard Worker title: `${upid === null ? tid : pid} schedule`, 127*6dbdd20aSAndroid Build Coastguard Worker tags: { 128*6dbdd20aSAndroid Build Coastguard Worker kind: PROCESS_SCHEDULING_TRACK_KIND, 129*6dbdd20aSAndroid Build Coastguard Worker }, 130*6dbdd20aSAndroid Build Coastguard Worker chips, 131*6dbdd20aSAndroid Build Coastguard Worker track: new ProcessSchedulingTrack(ctx, config, cpuCount, threads), 132*6dbdd20aSAndroid Build Coastguard Worker subtitle, 133*6dbdd20aSAndroid Build Coastguard Worker }); 134*6dbdd20aSAndroid Build Coastguard Worker } else { 135*6dbdd20aSAndroid Build Coastguard Worker const config: ProcessSummaryTrackConfig = { 136*6dbdd20aSAndroid Build Coastguard Worker pidForColor, 137*6dbdd20aSAndroid Build Coastguard Worker upid, 138*6dbdd20aSAndroid Build Coastguard Worker utid, 139*6dbdd20aSAndroid Build Coastguard Worker }; 140*6dbdd20aSAndroid Build Coastguard Worker 141*6dbdd20aSAndroid Build Coastguard Worker ctx.tracks.registerTrack({ 142*6dbdd20aSAndroid Build Coastguard Worker uri, 143*6dbdd20aSAndroid Build Coastguard Worker title: `${upid === null ? tid : pid} summary`, 144*6dbdd20aSAndroid Build Coastguard Worker tags: { 145*6dbdd20aSAndroid Build Coastguard Worker kind: PROCESS_SUMMARY_TRACK, 146*6dbdd20aSAndroid Build Coastguard Worker }, 147*6dbdd20aSAndroid Build Coastguard Worker chips, 148*6dbdd20aSAndroid Build Coastguard Worker track: new ProcessSummaryTrack(ctx.engine, config), 149*6dbdd20aSAndroid Build Coastguard Worker subtitle, 150*6dbdd20aSAndroid Build Coastguard Worker }); 151*6dbdd20aSAndroid Build Coastguard Worker } 152*6dbdd20aSAndroid Build Coastguard Worker } 153*6dbdd20aSAndroid Build Coastguard Worker } 154*6dbdd20aSAndroid Build Coastguard Worker 155*6dbdd20aSAndroid Build Coastguard Worker private async addKernelThreadSummary(ctx: Trace): Promise<void> { 156*6dbdd20aSAndroid Build Coastguard Worker const {engine} = ctx; 157*6dbdd20aSAndroid Build Coastguard Worker 158*6dbdd20aSAndroid Build Coastguard Worker // Identify kernel threads if this is a linux system trace, and sufficient 159*6dbdd20aSAndroid Build Coastguard Worker // process information is available. Kernel threads are identified by being 160*6dbdd20aSAndroid Build Coastguard Worker // children of kthreadd (always pid 2). 161*6dbdd20aSAndroid Build Coastguard Worker // The query will return the kthreadd process row first, which must exist 162*6dbdd20aSAndroid Build Coastguard Worker // for any other kthreads to be returned by the query. 163*6dbdd20aSAndroid Build Coastguard Worker // TODO(rsavitski): figure out how to handle the idle process (swapper), 164*6dbdd20aSAndroid Build Coastguard Worker // which has pid 0 but appears as a distinct process (with its own comm) on 165*6dbdd20aSAndroid Build Coastguard Worker // each cpu. It'd make sense to exclude its thread state track, but still 166*6dbdd20aSAndroid Build Coastguard Worker // put process-scoped tracks in this group. 167*6dbdd20aSAndroid Build Coastguard Worker const result = await engine.query(` 168*6dbdd20aSAndroid Build Coastguard Worker select 169*6dbdd20aSAndroid Build Coastguard Worker t.utid, p.upid, (case p.pid when 2 then 1 else 0 end) isKthreadd 170*6dbdd20aSAndroid Build Coastguard Worker from 171*6dbdd20aSAndroid Build Coastguard Worker thread t 172*6dbdd20aSAndroid Build Coastguard Worker join process p using (upid) 173*6dbdd20aSAndroid Build Coastguard Worker left join process parent on (p.parent_upid = parent.upid) 174*6dbdd20aSAndroid Build Coastguard Worker join 175*6dbdd20aSAndroid Build Coastguard Worker (select true from metadata m 176*6dbdd20aSAndroid Build Coastguard Worker where (m.name = 'system_name' and m.str_value = 'Linux') 177*6dbdd20aSAndroid Build Coastguard Worker union 178*6dbdd20aSAndroid Build Coastguard Worker select 1 from (select true from sched limit 1)) 179*6dbdd20aSAndroid Build Coastguard Worker where 180*6dbdd20aSAndroid Build Coastguard Worker p.pid = 2 or parent.pid = 2 181*6dbdd20aSAndroid Build Coastguard Worker order by isKthreadd desc 182*6dbdd20aSAndroid Build Coastguard Worker `); 183*6dbdd20aSAndroid Build Coastguard Worker 184*6dbdd20aSAndroid Build Coastguard Worker const it = result.iter({ 185*6dbdd20aSAndroid Build Coastguard Worker utid: NUM, 186*6dbdd20aSAndroid Build Coastguard Worker upid: NUM, 187*6dbdd20aSAndroid Build Coastguard Worker }); 188*6dbdd20aSAndroid Build Coastguard Worker 189*6dbdd20aSAndroid Build Coastguard Worker // Not applying kernel thread grouping. 190*6dbdd20aSAndroid Build Coastguard Worker if (!it.valid()) { 191*6dbdd20aSAndroid Build Coastguard Worker return; 192*6dbdd20aSAndroid Build Coastguard Worker } 193*6dbdd20aSAndroid Build Coastguard Worker 194*6dbdd20aSAndroid Build Coastguard Worker const config: ProcessSummaryTrackConfig = { 195*6dbdd20aSAndroid Build Coastguard Worker pidForColor: 2, 196*6dbdd20aSAndroid Build Coastguard Worker upid: it.upid, 197*6dbdd20aSAndroid Build Coastguard Worker utid: it.utid, 198*6dbdd20aSAndroid Build Coastguard Worker }; 199*6dbdd20aSAndroid Build Coastguard Worker 200*6dbdd20aSAndroid Build Coastguard Worker ctx.tracks.registerTrack({ 201*6dbdd20aSAndroid Build Coastguard Worker uri: '/kernel', 202*6dbdd20aSAndroid Build Coastguard Worker title: `Kernel thread summary`, 203*6dbdd20aSAndroid Build Coastguard Worker tags: { 204*6dbdd20aSAndroid Build Coastguard Worker kind: PROCESS_SUMMARY_TRACK, 205*6dbdd20aSAndroid Build Coastguard Worker }, 206*6dbdd20aSAndroid Build Coastguard Worker track: new ProcessSummaryTrack(ctx.engine, config), 207*6dbdd20aSAndroid Build Coastguard Worker }); 208*6dbdd20aSAndroid Build Coastguard Worker } 209*6dbdd20aSAndroid Build Coastguard Worker} 210