xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.ProcessSummary/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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