• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1--
2-- Copyright 2022 The Android Open Source Project
3--
4-- Licensed under the Apache License, Version 2.0 (the "License");
5-- you may not use this file except in compliance with the License.
6-- You may obtain a copy of the License at
7--
8--     https://www.apache.org/licenses/LICENSE-2.0
9--
10-- Unless required by applicable law or agreed to in writing, software
11-- distributed under the License is distributed on an "AS IS" BASIS,
12-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-- See the License for the specific language governing permissions and
14-- limitations under the License.
15--
16
17INCLUDE PERFETTO MODULE android.process_metadata;
18INCLUDE PERFETTO MODULE android.suspend;
19
20-- Count Binder transactions per process.
21CREATE PERFETTO VIEW android_binder_metrics_by_process(
22  -- Name of the process that started the binder transaction.
23  process_name INT,
24  -- PID of the process that started the binder transaction.
25  pid INT,
26  -- Name of the slice with binder transaction.
27  slice_name STRING,
28  -- Number of binder transactions in process in slice.
29  event_count INT
30) AS
31SELECT
32  process.name AS process_name,
33  process.pid AS pid,
34  slice.name AS slice_name,
35  COUNT(*) AS event_count
36FROM slice
37JOIN thread_track ON slice.track_id = thread_track.id
38JOIN thread ON thread.utid = thread_track.utid
39JOIN process ON thread.upid = process.upid
40WHERE
41  slice.name GLOB 'binder*'
42GROUP BY
43  process_name,
44  slice_name;
45
46CREATE PERFETTO TABLE _binder_txn_merged AS
47WITH maybe_broken_binder_txn AS (
48  -- Fetch the broken binder txns first, i.e, the txns that have children slices
49  -- They may be broken because synchronous txns are typically blocked sleeping while
50  -- waiting for a response.
51  -- These broken txns will be excluded below in the binder_txn CTE
52    SELECT ancestor.id
53    FROM slice
54    JOIN slice ancestor
55      ON ancestor.id = slice.parent_id
56    WHERE ancestor.name = 'binder transaction'
57    GROUP BY ancestor.id
58), nested_binder_txn AS (
59  -- Detect the non-broken cases which are just nested binder txns
60    SELECT slice_out AS id
61    FROM maybe_broken_binder_txn
62    JOIN following_flow(maybe_broken_binder_txn.id)
63  ), broken_binder_txn AS (
64  -- Exclude the nested txns from the 'maybe broken' set
65    SELECT * FROM maybe_broken_binder_txn
66    EXCEPT
67    SELECT * FROM nested_binder_txn
68  ),
69  -- Adding MATERIALIZED here matters in cases where there are few/no binder
70  -- transactions in the trace. Our cost estimation is not good enough to allow
71  -- the query planner to see through to this fact. Instead, our cost estimation
72  -- causes repeated queries on this table which is slow because it's an O(n)
73  -- query.
74  --
75  -- We should fix this by doing some (ideally all) of the following:
76  --  1) Add support for columnar tables in SQL which will allow for
77  --     "subsetting" the slice table to only contain binder transactions.
78  --  2) Make this query faster by adding improving string filtering.
79  --  3) Add caching so that even if these queries happen many times, they are
80  --     fast.
81  --  4) Improve cost estimation algorithm to allow the joins to happen the
82  --     right way around.
83  binder_txn AS MATERIALIZED (
84    SELECT
85      slice.id AS binder_txn_id,
86      process.name AS process_name,
87      thread.name AS thread_name,
88      thread.utid AS utid,
89      thread.tid AS tid,
90      process.pid AS pid,
91      process.upid AS upid,
92      slice.ts,
93      slice.dur,
94      thread.is_main_thread
95    FROM slice
96    JOIN thread_track ON slice.track_id = thread_track.id
97    JOIN thread USING (utid)
98    JOIN process USING (upid)
99    LEFT JOIN broken_binder_txn ON broken_binder_txn.id = slice.id
100    WHERE slice.name = 'binder transaction'
101    AND broken_binder_txn.id IS NULL
102  ),
103  binder_reply AS (
104    SELECT
105      binder_txn.*,
106      binder_reply.ts AS server_ts,
107      binder_reply.dur AS server_dur,
108      binder_reply.id AS binder_reply_id,
109      reply_thread.name AS server_thread,
110      reply_process.name AS server_process,
111      reply_thread.utid AS server_utid,
112      reply_thread.tid AS server_tid,
113      reply_process.pid AS server_pid,
114      reply_process.upid AS server_upid,
115      aidl.name AS aidl_name,
116      aidl.ts AS aidl_ts,
117      aidl.dur AS aidl_dur
118    FROM binder_txn
119    JOIN flow binder_flow ON binder_txn.binder_txn_id = binder_flow.slice_out
120    JOIN slice binder_reply ON binder_flow.slice_in = binder_reply.id
121    JOIN thread_track reply_thread_track
122      ON binder_reply.track_id = reply_thread_track.id
123    JOIN thread reply_thread ON reply_thread.utid = reply_thread_track.utid
124    JOIN process reply_process ON reply_process.upid = reply_thread.upid
125    LEFT JOIN slice aidl ON aidl.parent_id = binder_reply.id
126        AND (aidl.name GLOB 'AIDL::cpp*Server'
127             OR aidl.name GLOB 'AIDL::java*server'
128             OR aidl.name GLOB 'HIDL::*server')
129  )
130SELECT
131  MIN(aidl_name) AS aidl_name,
132  aidl_ts,
133  aidl_dur,
134  binder_txn_id,
135  process_name AS client_process,
136  thread_name AS client_thread,
137  upid AS client_upid,
138  utid AS client_utid,
139  tid AS client_tid,
140  pid AS client_pid,
141  is_main_thread,
142  ts AS client_ts,
143  dur AS client_dur,
144  binder_reply_id,
145  server_process,
146  server_thread,
147  server_upid,
148  server_utid,
149  server_tid,
150  server_pid,
151  server_ts,
152  server_dur
153FROM binder_reply
154WHERE client_dur != -1 AND server_dur != -1 AND client_dur >= server_dur
155GROUP BY
156  process_name,
157  thread_name,
158  binder_txn_id,
159  binder_reply_id;
160
161CREATE TABLE _oom_score AS
162  SELECT
163    process.upid,
164    CAST(c.value AS INT) AS value,
165    c.ts,
166    IFNULL(LEAD(ts) OVER (PARTITION BY upid ORDER BY ts), trace_end()) AS end_ts
167    FROM counter c
168         JOIN process_counter_track t ON c.track_id = t.id
169         JOIN process USING (upid)
170   WHERE t.name = 'oom_score_adj';
171
172CREATE INDEX _oom_score_idx ON _oom_score(upid, ts);
173
174-- Breakdown synchronous binder transactions per txn.
175-- It returns data about the client and server ends of every binder transaction.
176CREATE PERFETTO VIEW _sync_binder_metrics_by_txn AS
177SELECT binder.*, client_oom.value AS client_oom_score, server_oom.value AS server_oom_score
178FROM _binder_txn_merged binder
179LEFT JOIN _oom_score client_oom
180  ON
181    binder.client_upid = client_oom.upid
182    AND binder.client_ts BETWEEN client_oom.ts AND client_oom.end_ts
183LEFT JOIN _oom_score server_oom
184  ON
185    binder.server_upid = server_oom.upid
186    AND binder.server_ts BETWEEN server_oom.ts AND server_oom.end_ts;
187
188CREATE PERFETTO VIEW _binder_txn
189AS
190SELECT client_ts AS ts, client_dur AS dur, client_utid AS utid, *
191FROM _sync_binder_metrics_by_txn;
192
193CREATE PERFETTO VIEW _binder_reply
194AS
195SELECT server_ts AS ts, server_dur AS dur, server_utid AS utid, *
196FROM _sync_binder_metrics_by_txn;
197
198CREATE VIRTUAL TABLE _sp_binder_txn_thread_state
199USING
200  SPAN_JOIN(_binder_txn PARTITIONED utid, thread_state PARTITIONED utid);
201
202CREATE VIRTUAL TABLE _sp_binder_reply_thread_state
203USING
204  SPAN_JOIN(_binder_reply PARTITIONED utid, thread_state PARTITIONED utid);
205
206-- Aggregated thread_states on the client and server side per binder txn
207-- This builds on the data from |_sync_binder_metrics_by_txn| and
208-- for each end (client and server) of the transaction, it returns
209-- the aggregated sum of all the thread state durations.
210-- The |thread_state_type| column represents whether a given 'aggregated thread_state'
211-- row is on the client or server side. 'binder_txn' is client side and 'binder_reply'
212-- is server side.
213CREATE PERFETTO VIEW android_sync_binder_thread_state_by_txn(
214  -- slice id of the binder txn
215  binder_txn_id INT,
216  -- Client timestamp
217  client_ts INT,
218  -- Client tid
219  client_tid INT,
220  -- slice id of the binder reply
221  binder_reply_id INT,
222  -- Server timestamp
223  server_ts INT,
224  -- Server tid
225  server_tid INT,
226  -- whether thread state is on the txn or reply side
227  thread_state_type STRING,
228  -- a thread_state that occurred in the txn
229  thread_state STRING,
230  -- aggregated dur of the |thread_state| in the txn
231  thread_state_dur INT,
232  -- aggregated count of the |thread_state| in the txn
233  thread_state_count INT
234) AS
235SELECT
236  binder_txn_id,
237  client_ts,
238  client_tid,
239  binder_reply_id,
240  server_ts,
241  server_tid,
242  'binder_txn' AS thread_state_type,
243  state AS thread_state,
244  SUM(dur) AS thread_state_dur,
245  COUNT(dur) AS thread_state_count
246FROM _sp_binder_txn_thread_state
247GROUP BY binder_txn_id, binder_reply_id, thread_state_type, thread_state
248UNION ALL
249SELECT
250  binder_txn_id,
251  client_ts,
252  client_tid,
253  binder_reply_id,
254  server_ts,
255  server_tid,
256  'binder_reply' AS thread_state_type,
257  state AS thread_state,
258  SUM(dur) AS thread_state_dur,
259  COUNT(dur) AS thread_state_count
260FROM _sp_binder_reply_thread_state
261GROUP BY binder_txn_id, binder_reply_id, thread_state_type, thread_state;
262
263-- Aggregated blocked_functions on the client and server side per binder txn
264-- This builds on the data from |_sync_binder_metrics_by_txn| and
265-- for each end (client and server) of the transaction, it returns
266-- the aggregated sum of all the kernel blocked function durations.
267-- The |thread_state_type| column represents whether a given 'aggregated blocked_function'
268-- row is on the client or server side. 'binder_txn' is client side and 'binder_reply'
269-- is server side.
270CREATE PERFETTO VIEW android_sync_binder_blocked_functions_by_txn(
271  -- slice id of the binder txn
272  binder_txn_id INT,
273  -- Client ts
274  client_ts INT,
275  -- Client tid
276  client_tid INT,
277  -- slice id of the binder reply
278  binder_reply_id INT,
279  -- Server ts
280  server_ts INT,
281  -- Server tid
282  server_tid INT,
283  -- whether thread state is on the txn or reply side
284  thread_state_type STRING,
285  -- blocked kernel function in a thread state
286  blocked_function STRING,
287  -- aggregated dur of the |blocked_function| in the txn
288  blocked_function_dur INT,
289  -- aggregated count of the |blocked_function| in the txn
290  blocked_function_count INT
291) AS
292SELECT
293  binder_txn_id,
294  client_ts,
295  client_tid,
296  binder_reply_id,
297  server_ts,
298  server_tid,
299  'binder_txn' AS thread_state_type,
300  blocked_function,
301  SUM(dur) AS blocked_function_dur,
302  COUNT(dur) AS blocked_function_count
303FROM _sp_binder_txn_thread_state
304WHERE blocked_function IS NOT NULL
305GROUP BY binder_txn_id, binder_reply_id, blocked_function
306UNION ALL
307SELECT
308  binder_txn_id,
309  client_ts,
310  client_tid,
311  binder_reply_id,
312  server_ts,
313  server_tid,
314  'binder_reply' AS thread_state_type,
315  blocked_function,
316  SUM(dur) AS blocked_function_dur,
317  COUNT(dur) AS blocked_function_count
318FROM _sp_binder_reply_thread_state
319WHERE blocked_function IS NOT NULL
320GROUP BY binder_txn_id, binder_reply_id, blocked_function;
321
322CREATE PERFETTO TABLE _async_binder_reply AS
323WITH async_reply AS MATERIALIZED (
324  SELECT id, ts, dur, track_id, name
325  FROM slice
326  WHERE
327    name GLOB 'AIDL::cpp*Server'
328    OR name GLOB 'AIDL::java*server'
329    OR name GLOB 'HIDL::*server'
330    OR name = 'binder async rcv'
331) SELECT *, LEAD(name) OVER (PARTITION BY track_id ORDER BY ts) AS next_name,
332    LEAD(ts) OVER (PARTITION BY track_id ORDER BY ts) AS next_ts,
333    LEAD(dur) OVER (PARTITION BY track_id ORDER BY ts) AS next_dur
334    FROM async_reply;
335
336CREATE PERFETTO TABLE _binder_async_txn_raw AS
337SELECT
338  slice.id AS binder_txn_id,
339  process.name AS client_process,
340  thread.name AS client_thread,
341  process.upid AS client_upid,
342  thread.utid AS client_utid,
343  thread.tid AS client_tid,
344  process.pid AS client_pid,
345  thread.is_main_thread,
346  slice.ts AS client_ts,
347  slice.dur AS client_dur
348FROM slice
349JOIN thread_track
350  ON slice.track_id = thread_track.id
351JOIN thread
352  USING (utid)
353JOIN process
354  USING (upid)
355WHERE slice.name = 'binder transaction async';
356
357CREATE PERFETTO TABLE _binder_async_txn AS
358SELECT
359  IIF(binder_reply.next_name = 'binder async rcv', NULL, binder_reply.next_name) AS aidl_name,
360  IIF(binder_reply.next_name = 'binder async rcv', NULL, binder_reply.next_ts) AS aidl_ts,
361  IIF(binder_reply.next_name = 'binder async rcv', NULL, binder_reply.next_dur) AS aidl_dur,
362  binder_txn.*,
363  binder_reply.id AS binder_reply_id,
364  reply_process.name AS server_process,
365  reply_thread.name AS server_thread,
366  reply_process.upid AS server_upid,
367  reply_thread.utid AS server_utid,
368  reply_thread.tid AS server_tid,
369  reply_process.pid AS server_pid,
370  binder_reply.ts AS server_ts,
371  binder_reply.dur AS server_dur
372FROM _binder_async_txn_raw binder_txn
373JOIN flow binder_flow
374  ON binder_txn.binder_txn_id = binder_flow.slice_out
375JOIN _async_binder_reply binder_reply
376  ON binder_flow.slice_in = binder_reply.id
377JOIN thread_track reply_thread_track
378  ON binder_reply.track_id = reply_thread_track.id
379JOIN thread reply_thread
380  ON reply_thread.utid = reply_thread_track.utid
381JOIN process reply_process
382  ON reply_process.upid = reply_thread.upid
383WHERE binder_reply.name = 'binder async rcv';
384
385-- Breakdown asynchronous binder transactions per txn.
386-- It returns data about the client and server ends of every binder transaction async.
387CREATE PERFETTO VIEW _async_binder_metrics_by_txn AS
388SELECT binder.*, client_oom.value AS client_oom_score, server_oom.value AS server_oom_score
389FROM _binder_async_txn binder
390LEFT JOIN _oom_score client_oom
391  ON
392    binder.client_upid = client_oom.upid
393    AND binder.client_ts BETWEEN client_oom.ts AND client_oom.end_ts
394LEFT JOIN _oom_score server_oom
395  ON
396    binder.server_upid = server_oom.upid
397    AND binder.server_ts BETWEEN server_oom.ts AND server_oom.end_ts;
398
399-- Breakdown binder transactions per txn.
400-- It returns data about the client and server ends of every binder transaction async.
401CREATE PERFETTO TABLE android_binder_txns(
402  -- name of the binder interface if existing.
403  aidl_name STRING,
404  -- Timestamp the binder interface name was emitted. Proxy to 'ts' and 'dur' for async txns.
405  aidl_ts INT,
406  -- Duration of the binder interface name. Proxy to 'ts' and 'dur' for async txns.
407  aidl_dur INT,
408  -- slice id of the binder txn.
409  binder_txn_id INT,
410  -- name of the client process.
411  client_process STRING,
412  -- name of the client thread.
413  client_thread STRING,
414  -- Upid of the client process.
415  client_upid INT,
416  -- Utid of the client thread.
417  client_utid INT,
418  -- Tid of the client thread.
419  client_tid INT,
420  -- Pid of the client thread.
421  client_pid INT,
422  -- Whether the txn was initiated from the main thread of the client process.
423  is_main_thread BOOL,
424  -- timestamp of the client txn.
425  client_ts INT,
426  -- wall clock dur of the client txn.
427  client_dur INT,
428  -- slice id of the binder reply.
429  binder_reply_id INT,
430  -- name of the server process.
431  server_process STRING,
432  -- name of the server thread.
433  server_thread STRING,
434  -- Upid of the server process.
435  server_upid INT,
436  -- Utid of the server thread.
437  server_utid INT,
438  -- Tid of the server thread.
439  server_tid INT,
440  -- Pid of the server thread.
441  server_pid INT,
442  -- timestamp of the server txn.
443  server_ts INT,
444  -- wall clock dur of the server txn.
445  server_dur INT,
446  -- oom score of the client process at the start of the txn.
447  client_oom_score INT,
448  -- oom score of the server process at the start of the reply.
449  server_oom_score INT,
450  -- whether the txn is synchronous or async (oneway).
451  is_sync BOOL,
452  -- monotonic clock dur of the client txn.
453  client_monotonic_dur INT,
454  -- monotonic clock dur of the server txn.
455  server_monotonic_dur INT,
456  -- Client package version_code.
457  client_package_version_code INT,
458  -- Server package version_code.
459  server_package_version_code INT,
460  -- Whether client package is debuggable.
461  is_client_package_debuggable INT,
462  -- Whether server package is debuggable.
463  is_server_package_debuggable INT
464) AS WITH all_binder AS (
465  SELECT *, 1 AS is_sync FROM _sync_binder_metrics_by_txn
466UNION ALL
467SELECT *, 0 AS is_sync FROM _async_binder_metrics_by_txn
468) SELECT
469  all_binder.*,
470  _extract_duration_without_suspend(client_ts, client_dur) AS client_monotonic_dur,
471  _extract_duration_without_suspend(server_ts, server_dur) AS server_monotonic_dur,
472  client_process_metadata.version_code AS client_package_version_code,
473  server_process_metadata.version_code AS server_package_version_code,
474  client_process_metadata.debuggable AS is_client_package_debuggable,
475  server_process_metadata.debuggable AS is_server_package_debuggable
476FROM all_binder
477LEFT JOIN android_process_metadata client_process_metadata
478  ON all_binder.client_upid = client_process_metadata.upid
479LEFT JOIN android_process_metadata server_process_metadata
480  ON all_binder.server_upid = server_process_metadata.upid;
481
482-- Returns a DAG of all outgoing binder txns from a process.
483-- The roots of the graph are the threads making the txns and the graph flows from:
484-- thread -> server_process -> AIDL interface -> AIDL method.
485-- The weights of each node represent the wall execution time in the server_process.
486CREATE PERFETTO FUNCTION android_binder_outgoing_graph(
487  -- Upid of process to generate an outgoing graph for.
488  upid INT)
489RETURNS TABLE(
490  -- Pprof of outgoing binder txns.
491  pprof BYTES) AS
492WITH threads AS (
493  SELECT binder_txn_id, CAT_STACKS(client_thread) AS stack
494  FROM android_binder_txns
495  WHERE ($upid IS NOT NULL AND client_upid = $upid) OR ($upid IS NULL)
496), server_process AS (
497  SELECT binder_txn_id, CAT_STACKS(stack, server_process) AS stack
498  FROM android_binder_txns
499  JOIN threads USING(binder_txn_id)
500), end_points AS (
501  SELECT binder_txn_id,
502         CAT_STACKS(stack, STR_SPLIT(aidl_name, '::', IIF(aidl_name GLOB 'AIDL*', 2, 1))) AS stack
503  FROM android_binder_txns
504  JOIN server_process USING(binder_txn_id)
505), aidl_names AS (
506  SELECT binder_txn_id, server_dur,
507         CAT_STACKS(stack, STR_SPLIT(aidl_name, '::', IIF(aidl_name GLOB 'AIDL*', 3, 2))) AS stack
508  FROM android_binder_txns
509  JOIN end_points USING(binder_txn_id)
510) SELECT EXPERIMENTAL_PROFILE(stack, 'duration', 'ns', server_dur) AS pprof
511  FROM aidl_names;
512
513-- Returns a DAG of all incoming binder txns from a process.
514-- The roots of the graph are the clients making the txns and the graph flows from:
515-- client_process -> AIDL interface -> AIDL method.
516-- The weights of each node represent the wall execution time in the server_process.
517CREATE PERFETTO FUNCTION android_binder_incoming_graph(
518  -- Upid of process to generate an incoming graph for.
519  upid INT)
520RETURNS TABLE(
521  -- Pprof of incoming binder txns.
522  pprof BYTES) AS
523WITH client_process AS (
524  SELECT binder_txn_id, CAT_STACKS(client_process) AS stack
525  FROM android_binder_txns
526  WHERE ($upid IS NOT NULL AND server_upid = $upid) OR ($upid IS NULL)
527), end_points AS (
528  SELECT binder_txn_id,
529         CAT_STACKS(stack, STR_SPLIT(aidl_name, '::', IIF(aidl_name GLOB 'AIDL*', 2, 1))) AS stack
530  FROM android_binder_txns
531  JOIN client_process USING(binder_txn_id)
532), aidl_names AS (
533  SELECT binder_txn_id, server_dur,
534         CAT_STACKS(stack, STR_SPLIT(aidl_name, '::', IIF(aidl_name GLOB 'AIDL*', 3, 2))) AS stack
535  FROM android_binder_txns
536  JOIN end_points USING(binder_txn_id)
537) SELECT EXPERIMENTAL_PROFILE(stack, 'duration', 'ns', server_dur) AS pprof
538  FROM aidl_names;
539
540-- Returns a graph of all binder txns in a trace.
541-- The nodes are client_process and server_process.
542-- The weights of each node represent the wall execution time in the server_process.
543CREATE PERFETTO FUNCTION android_binder_graph(
544  -- Matches txns from client_processes greater than or equal to the OOM score.
545  min_client_oom_score INT,
546  -- Matches txns from client_processes less than or equal to the OOM score.
547  max_client_oom_score INT,
548  -- Matches txns to server_processes greater than or equal to the OOM score.
549  min_server_oom_score INT,
550  -- Matches txns to server_processes less than or equal to the OOM score.
551  max_server_oom_score INT)
552RETURNS TABLE(
553  -- Pprof of binder txns.
554  pprof BYTES) AS
555WITH clients AS (
556  SELECT binder_txn_id, CAT_STACKS(client_process) AS stack
557   FROM android_binder_txns
558   WHERE client_oom_score BETWEEN $min_client_oom_score AND $max_client_oom_score
559), servers AS (
560  SELECT binder_txn_id, server_dur, CAT_STACKS(stack, server_process) AS stack
561  FROM android_binder_txns
562  JOIN clients USING(binder_txn_id)
563  WHERE server_oom_score BETWEEN $min_server_oom_score AND $max_server_oom_score
564) SELECT EXPERIMENTAL_PROFILE(stack, 'duration', 'ns', server_dur) AS pprof
565  FROM servers;
566