xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.AndroidClientServer/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2023 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 {NUM, STR} from '../../trace_processor/query_result';
16*6dbdd20aSAndroid Build Coastguard Workerimport {Trace} from '../../public/trace';
17*6dbdd20aSAndroid Build Coastguard Workerimport {PerfettoPlugin} from '../../public/plugin';
18*6dbdd20aSAndroid Build Coastguard Workerimport {addDebugSliceTrack} from '../../components/tracks/debug_tracks';
19*6dbdd20aSAndroid Build Coastguard Worker
20*6dbdd20aSAndroid Build Coastguard Workerexport default class implements PerfettoPlugin {
21*6dbdd20aSAndroid Build Coastguard Worker  static readonly id = 'dev.perfetto.AndroidClientServer';
22*6dbdd20aSAndroid Build Coastguard Worker  async onTraceLoad(ctx: Trace): Promise<void> {
23*6dbdd20aSAndroid Build Coastguard Worker    ctx.commands.registerCommand({
24*6dbdd20aSAndroid Build Coastguard Worker      id: 'dev.perfetto.AndroidClientServer#ThreadRuntimeIPC',
25*6dbdd20aSAndroid Build Coastguard Worker      name: 'Show dependencies in client server model',
26*6dbdd20aSAndroid Build Coastguard Worker      callback: async (sliceId) => {
27*6dbdd20aSAndroid Build Coastguard Worker        if (sliceId === undefined) {
28*6dbdd20aSAndroid Build Coastguard Worker          sliceId = prompt('Enter a slice id', '');
29*6dbdd20aSAndroid Build Coastguard Worker          if (sliceId === null) return;
30*6dbdd20aSAndroid Build Coastguard Worker        }
31*6dbdd20aSAndroid Build Coastguard Worker        await ctx.engine.query(`
32*6dbdd20aSAndroid Build Coastguard Worker          include perfetto module android.binder;
33*6dbdd20aSAndroid Build Coastguard Worker          include perfetto module graphs.search;
34*6dbdd20aSAndroid Build Coastguard Worker
35*6dbdd20aSAndroid Build Coastguard Worker          create or replace perfetto table __binder_for_slice_${sliceId} as
36*6dbdd20aSAndroid Build Coastguard Worker          with s as materialized (
37*6dbdd20aSAndroid Build Coastguard Worker            select slice.id, ts, ts + dur as ts_end, dur, upid
38*6dbdd20aSAndroid Build Coastguard Worker            from thread_slice slice
39*6dbdd20aSAndroid Build Coastguard Worker            where slice.id = ${sliceId}
40*6dbdd20aSAndroid Build Coastguard Worker          ),
41*6dbdd20aSAndroid Build Coastguard Worker          child_binder_txns_for_slice as materialized (
42*6dbdd20aSAndroid Build Coastguard Worker            select
43*6dbdd20aSAndroid Build Coastguard Worker              (select id from s) as source_node_id,
44*6dbdd20aSAndroid Build Coastguard Worker              binder_txn_id as dest_node_id
45*6dbdd20aSAndroid Build Coastguard Worker            from descendant_slice((select id from s)) as desc
46*6dbdd20aSAndroid Build Coastguard Worker            join android_binder_txns txns on desc.id = txns.binder_txn_id
47*6dbdd20aSAndroid Build Coastguard Worker          ),
48*6dbdd20aSAndroid Build Coastguard Worker          binder_txns_in_slice_intervals as materialized (
49*6dbdd20aSAndroid Build Coastguard Worker            select
50*6dbdd20aSAndroid Build Coastguard Worker              binder_txn_id as source_node_id,
51*6dbdd20aSAndroid Build Coastguard Worker              binder_reply_id as dest_node_id
52*6dbdd20aSAndroid Build Coastguard Worker            from android_binder_txns
53*6dbdd20aSAndroid Build Coastguard Worker            where client_ts > (select ts from s)
54*6dbdd20aSAndroid Build Coastguard Worker              and client_ts < (select ts + dur from s)
55*6dbdd20aSAndroid Build Coastguard Worker          ),
56*6dbdd20aSAndroid Build Coastguard Worker          nested_binder_txns_in_slice_interval as materialized (
57*6dbdd20aSAndroid Build Coastguard Worker            select
58*6dbdd20aSAndroid Build Coastguard Worker              parent.binder_reply_id as source_node_id,
59*6dbdd20aSAndroid Build Coastguard Worker              child.binder_txn_id as dest_node_id
60*6dbdd20aSAndroid Build Coastguard Worker            from android_binder_txns parent
61*6dbdd20aSAndroid Build Coastguard Worker            join descendant_slice(parent.binder_reply_id) desc
62*6dbdd20aSAndroid Build Coastguard Worker            join android_binder_txns child on desc.id = child.binder_txn_id
63*6dbdd20aSAndroid Build Coastguard Worker            where parent.server_ts > (select ts from s)
64*6dbdd20aSAndroid Build Coastguard Worker              and parent.server_ts < (select ts + dur from s)
65*6dbdd20aSAndroid Build Coastguard Worker          ),
66*6dbdd20aSAndroid Build Coastguard Worker          all_binder_txns_considered as materialized (
67*6dbdd20aSAndroid Build Coastguard Worker            select * from child_binder_txns_for_slice
68*6dbdd20aSAndroid Build Coastguard Worker            union
69*6dbdd20aSAndroid Build Coastguard Worker            select * from binder_txns_in_slice_intervals
70*6dbdd20aSAndroid Build Coastguard Worker            union
71*6dbdd20aSAndroid Build Coastguard Worker            select * from nested_binder_txns_in_slice_interval
72*6dbdd20aSAndroid Build Coastguard Worker          )
73*6dbdd20aSAndroid Build Coastguard Worker          select
74*6dbdd20aSAndroid Build Coastguard Worker            dfs.node_id as id,
75*6dbdd20aSAndroid Build Coastguard Worker            coalesce(client.client_ts, server.client_ts, slice.ts) as ts,
76*6dbdd20aSAndroid Build Coastguard Worker            coalesce(client.client_dur, server.client_dur, slice.dur) as dur,
77*6dbdd20aSAndroid Build Coastguard Worker            coalesce(
78*6dbdd20aSAndroid Build Coastguard Worker              client.aidl_name,
79*6dbdd20aSAndroid Build Coastguard Worker              server.aidl_name,
80*6dbdd20aSAndroid Build Coastguard Worker              iif(
81*6dbdd20aSAndroid Build Coastguard Worker                server.binder_reply_id is not null,
82*6dbdd20aSAndroid Build Coastguard Worker                coalesce(
83*6dbdd20aSAndroid Build Coastguard Worker                  server.server_process,
84*6dbdd20aSAndroid Build Coastguard Worker                  server.server_thread,
85*6dbdd20aSAndroid Build Coastguard Worker                  'Unknown server'
86*6dbdd20aSAndroid Build Coastguard Worker                ),
87*6dbdd20aSAndroid Build Coastguard Worker                slice.name
88*6dbdd20aSAndroid Build Coastguard Worker              )
89*6dbdd20aSAndroid Build Coastguard Worker            ) name,
90*6dbdd20aSAndroid Build Coastguard Worker            coalesce(
91*6dbdd20aSAndroid Build Coastguard Worker              client.client_utid,
92*6dbdd20aSAndroid Build Coastguard Worker              server.server_utid,
93*6dbdd20aSAndroid Build Coastguard Worker              thread_track.utid
94*6dbdd20aSAndroid Build Coastguard Worker            ) as utid,
95*6dbdd20aSAndroid Build Coastguard Worker            case
96*6dbdd20aSAndroid Build Coastguard Worker              when client.binder_txn_id is not null then 'client'
97*6dbdd20aSAndroid Build Coastguard Worker              when server.binder_reply_id is not null then 'server'
98*6dbdd20aSAndroid Build Coastguard Worker              else 'slice'
99*6dbdd20aSAndroid Build Coastguard Worker            end as slice_type,
100*6dbdd20aSAndroid Build Coastguard Worker            coalesce(client.is_sync, server.is_sync, true) as is_sync
101*6dbdd20aSAndroid Build Coastguard Worker          from graph_reachable_dfs!(
102*6dbdd20aSAndroid Build Coastguard Worker            all_binder_txns_considered,
103*6dbdd20aSAndroid Build Coastguard Worker            (select id as node_id from s)
104*6dbdd20aSAndroid Build Coastguard Worker          ) dfs
105*6dbdd20aSAndroid Build Coastguard Worker          join slice on dfs.node_id = slice.id
106*6dbdd20aSAndroid Build Coastguard Worker          join thread_track on slice.track_id = thread_track.id
107*6dbdd20aSAndroid Build Coastguard Worker          left join android_binder_txns client on dfs.node_id = client.binder_txn_id
108*6dbdd20aSAndroid Build Coastguard Worker          left join android_binder_txns server on dfs.node_id = server.binder_reply_id
109*6dbdd20aSAndroid Build Coastguard Worker          order by ts;
110*6dbdd20aSAndroid Build Coastguard Worker        `);
111*6dbdd20aSAndroid Build Coastguard Worker        await ctx.engine.query(`
112*6dbdd20aSAndroid Build Coastguard Worker          include perfetto module intervals.intersect;
113*6dbdd20aSAndroid Build Coastguard Worker
114*6dbdd20aSAndroid Build Coastguard Worker          create or replace perfetto table __enhanced_binder_for_slice_${sliceId} as
115*6dbdd20aSAndroid Build Coastguard Worker          with foo as (
116*6dbdd20aSAndroid Build Coastguard Worker            select
117*6dbdd20aSAndroid Build Coastguard Worker              bfs.id as binder_id,
118*6dbdd20aSAndroid Build Coastguard Worker              bfs.name as binder_name,
119*6dbdd20aSAndroid Build Coastguard Worker              ii.ts,
120*6dbdd20aSAndroid Build Coastguard Worker              ii.dur,
121*6dbdd20aSAndroid Build Coastguard Worker              tstate.utid,
122*6dbdd20aSAndroid Build Coastguard Worker              thread.upid,
123*6dbdd20aSAndroid Build Coastguard Worker              tstate.cpu,
124*6dbdd20aSAndroid Build Coastguard Worker              tstate.state,
125*6dbdd20aSAndroid Build Coastguard Worker              tstate.io_wait,
126*6dbdd20aSAndroid Build Coastguard Worker              (
127*6dbdd20aSAndroid Build Coastguard Worker                select name
128*6dbdd20aSAndroid Build Coastguard Worker                from thread_slice tslice
129*6dbdd20aSAndroid Build Coastguard Worker                where tslice.utid = tstate.utid and tslice.ts < ii.ts
130*6dbdd20aSAndroid Build Coastguard Worker                order by ts desc
131*6dbdd20aSAndroid Build Coastguard Worker                limit 1
132*6dbdd20aSAndroid Build Coastguard Worker              ) as enclosing_slice_name
133*6dbdd20aSAndroid Build Coastguard Worker            from _interval_intersect!(
134*6dbdd20aSAndroid Build Coastguard Worker              (
135*6dbdd20aSAndroid Build Coastguard Worker                select id, ts, dur
136*6dbdd20aSAndroid Build Coastguard Worker                from __binder_for_slice_${sliceId}
137*6dbdd20aSAndroid Build Coastguard Worker                where slice_type IN ('slice', 'server')
138*6dbdd20aSAndroid Build Coastguard Worker                  and is_sync
139*6dbdd20aSAndroid Build Coastguard Worker                  and dur > 0
140*6dbdd20aSAndroid Build Coastguard Worker              ),
141*6dbdd20aSAndroid Build Coastguard Worker              (
142*6dbdd20aSAndroid Build Coastguard Worker                select id, ts, dur
143*6dbdd20aSAndroid Build Coastguard Worker                from thread_state tstate
144*6dbdd20aSAndroid Build Coastguard Worker                where
145*6dbdd20aSAndroid Build Coastguard Worker                  tstate.utid in (
146*6dbdd20aSAndroid Build Coastguard Worker                    select distinct utid
147*6dbdd20aSAndroid Build Coastguard Worker                    from __binder_for_slice_${sliceId}
148*6dbdd20aSAndroid Build Coastguard Worker                    where
149*6dbdd20aSAndroid Build Coastguard Worker                      slice_type IN ('slice', 'server')
150*6dbdd20aSAndroid Build Coastguard Worker                      and is_sync
151*6dbdd20aSAndroid Build Coastguard Worker                      and dur > 0
152*6dbdd20aSAndroid Build Coastguard Worker                  )
153*6dbdd20aSAndroid Build Coastguard Worker                  and dur > 0
154*6dbdd20aSAndroid Build Coastguard Worker              ),
155*6dbdd20aSAndroid Build Coastguard Worker              ()
156*6dbdd20aSAndroid Build Coastguard Worker            ) ii
157*6dbdd20aSAndroid Build Coastguard Worker            join __binder_for_slice_${sliceId} bfs on ii.id_0 = bfs.id
158*6dbdd20aSAndroid Build Coastguard Worker            join thread_state tstate on ii.id_1 = tstate.id
159*6dbdd20aSAndroid Build Coastguard Worker            join thread using (utid)
160*6dbdd20aSAndroid Build Coastguard Worker            where bfs.utid = tstate.utid
161*6dbdd20aSAndroid Build Coastguard Worker          )
162*6dbdd20aSAndroid Build Coastguard Worker          select
163*6dbdd20aSAndroid Build Coastguard Worker            *,
164*6dbdd20aSAndroid Build Coastguard Worker            case
165*6dbdd20aSAndroid Build Coastguard Worker              when state = 'S' and enclosing_slice_name = 'binder transaction' then 'Waiting for server'
166*6dbdd20aSAndroid Build Coastguard Worker              when state = 'S' and enclosing_slice_name GLOB 'Lock*' then 'Waiting for lock'
167*6dbdd20aSAndroid Build Coastguard Worker              when state = 'S' and enclosing_slice_name GLOB 'Monitor*' then 'Waiting for contention'
168*6dbdd20aSAndroid Build Coastguard Worker              when state = 'S' then 'Sleeping'
169*6dbdd20aSAndroid Build Coastguard Worker              when state = 'R' then 'Waiting for CPU'
170*6dbdd20aSAndroid Build Coastguard Worker              when state = 'Running' then 'Running on CPU ' || foo.cpu
171*6dbdd20aSAndroid Build Coastguard Worker              when state GLOB 'R*' then 'Runnable'
172*6dbdd20aSAndroid Build Coastguard Worker              when state GLOB 'D*' and io_wait then 'IO'
173*6dbdd20aSAndroid Build Coastguard Worker              when state GLOB 'D*' and not io_wait then 'Unint-sleep'
174*6dbdd20aSAndroid Build Coastguard Worker            end as name
175*6dbdd20aSAndroid Build Coastguard Worker          from foo
176*6dbdd20aSAndroid Build Coastguard Worker          order by binder_id;
177*6dbdd20aSAndroid Build Coastguard Worker        `);
178*6dbdd20aSAndroid Build Coastguard Worker
179*6dbdd20aSAndroid Build Coastguard Worker        const res = await ctx.engine.query(`
180*6dbdd20aSAndroid Build Coastguard Worker          select id, name
181*6dbdd20aSAndroid Build Coastguard Worker          from __binder_for_slice_${sliceId} bfs
182*6dbdd20aSAndroid Build Coastguard Worker          where slice_type IN ('slice', 'server')
183*6dbdd20aSAndroid Build Coastguard Worker            and dur > 0
184*6dbdd20aSAndroid Build Coastguard Worker          order by ts
185*6dbdd20aSAndroid Build Coastguard Worker        `);
186*6dbdd20aSAndroid Build Coastguard Worker        const it = res.iter({
187*6dbdd20aSAndroid Build Coastguard Worker          id: NUM,
188*6dbdd20aSAndroid Build Coastguard Worker          name: STR,
189*6dbdd20aSAndroid Build Coastguard Worker        });
190*6dbdd20aSAndroid Build Coastguard Worker        for (; it.valid(); it.next()) {
191*6dbdd20aSAndroid Build Coastguard Worker          await addDebugSliceTrack({
192*6dbdd20aSAndroid Build Coastguard Worker            trace: ctx,
193*6dbdd20aSAndroid Build Coastguard Worker            data: {
194*6dbdd20aSAndroid Build Coastguard Worker              sqlSource: `
195*6dbdd20aSAndroid Build Coastguard Worker                SELECT ts, dur, name
196*6dbdd20aSAndroid Build Coastguard Worker                FROM __enhanced_binder_for_slice_${sliceId}
197*6dbdd20aSAndroid Build Coastguard Worker                WHERE binder_id = ${it.id}
198*6dbdd20aSAndroid Build Coastguard Worker              `,
199*6dbdd20aSAndroid Build Coastguard Worker            },
200*6dbdd20aSAndroid Build Coastguard Worker            title: it.name,
201*6dbdd20aSAndroid Build Coastguard Worker          });
202*6dbdd20aSAndroid Build Coastguard Worker        }
203*6dbdd20aSAndroid Build Coastguard Worker      },
204*6dbdd20aSAndroid Build Coastguard Worker    });
205*6dbdd20aSAndroid Build Coastguard Worker  }
206*6dbdd20aSAndroid Build Coastguard Worker}
207