• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1--
2-- Copyright 2023 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.suspend;
18
19-- Extracts the blocking thread from a slice name
20CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_blocking_thread(
21    -- Name of slice
22    slice_name STRING
23)
24-- Blocking thread
25RETURNS STRING AS
26SELECT
27  str_split(str_split($slice_name, "with owner ", 1), " (", 0);
28
29-- Extracts the blocking thread tid from a slice name
30CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_blocking_tid(
31    -- Name of slice
32    slice_name STRING
33)
34-- Blocking thread tid
35RETURNS LONG AS
36SELECT
37  cast_int!(STR_SPLIT(STR_SPLIT($slice_name, " (", 1), ")", 0));
38
39-- Extracts the blocking method from a slice name
40CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_blocking_method(
41    -- Name of slice
42    slice_name STRING
43)
44-- Blocking thread
45RETURNS STRING AS
46SELECT
47  str_split(str_split($slice_name, ") at ", 1), "(", 0) || "(" || str_split(str_split($slice_name, ") at ", 1), "(", 1);
48
49-- Extracts a shortened form of the blocking method name from a slice name.
50-- The shortened form discards the parameter and return
51-- types.
52CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_short_blocking_method(
53    -- Name of slice
54    slice_name STRING
55)
56-- Blocking thread
57RETURNS STRING AS
58SELECT
59  str_split(
60    str_split(android_extract_android_monitor_contention_blocking_method($slice_name), " ", 1),
61    "(",
62    0
63  );
64
65-- Extracts the monitor contention blocked method from a slice name
66CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_blocked_method(
67    -- Name of slice
68    slice_name STRING
69)
70-- Blocking thread
71RETURNS STRING AS
72SELECT
73  str_split(str_split($slice_name, "blocking from ", 1), "(", 0) || "(" || str_split(str_split($slice_name, "blocking from ", 1), "(", 1);
74
75-- Extracts a shortened form of the monitor contention blocked method name
76-- from a slice name. The shortened form discards the parameter and return
77-- types.
78CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_short_blocked_method(
79    -- Name of slice
80    slice_name STRING
81)
82-- Blocking thread
83RETURNS STRING AS
84SELECT
85  str_split(
86    str_split(android_extract_android_monitor_contention_blocked_method($slice_name), " ", 1),
87    "(",
88    0
89  );
90
91-- Extracts the number of waiters on the monitor from a slice name
92CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_waiter_count(
93    -- Name of slice
94    slice_name STRING
95)
96-- Count of waiters on the lock
97RETURNS LONG AS
98SELECT
99  cast_int!(STR_SPLIT(STR_SPLIT($slice_name, "waiters=", 1), " ", 0));
100
101-- Extracts the monitor contention blocking source location from a slice name
102CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_blocking_src(
103    -- Name of slice
104    slice_name STRING
105)
106-- Blocking thread
107RETURNS STRING AS
108SELECT
109  str_split(str_split($slice_name, ")(", 1), ")", 0);
110
111-- Extracts the monitor contention blocked source location from a slice name
112CREATE PERFETTO FUNCTION android_extract_android_monitor_contention_blocked_src(
113    -- Name of slice
114    slice_name STRING
115)
116-- Blocking thread
117RETURNS STRING AS
118SELECT
119  str_split(str_split($slice_name, ")(", 2), ")", 0);
120
121CREATE PERFETTO TABLE _valid_android_monitor_contention AS
122SELECT
123  slice.id AS id
124FROM slice
125LEFT JOIN slice AS child
126  ON child.parent_id = slice.id
127LEFT JOIN slice AS grand_child
128  ON grand_child.parent_id = child.id
129WHERE
130  slice.name GLOB 'monitor contention*'
131  AND (
132    child.name GLOB 'Lock contention*' OR child.name IS NULL
133  )
134  AND (
135    grand_child.name IS NULL
136  )
137GROUP BY
138  slice.id;
139
140-- Contains parsed monitor contention slices.
141CREATE PERFETTO TABLE android_monitor_contention (
142  -- Name of the method holding the lock.
143  blocking_method STRING,
144  -- Blocked_method without arguments and return types.
145  blocked_method STRING,
146  -- Blocking_method without arguments and return types.
147  short_blocking_method STRING,
148  -- Blocked_method without arguments and return types.
149  short_blocked_method STRING,
150  -- File location of blocking_method in form <filename:linenumber>.
151  blocking_src STRING,
152  -- File location of blocked_method in form <filename:linenumber>.
153  blocked_src STRING,
154  -- Zero indexed number of threads trying to acquire the lock.
155  waiter_count LONG,
156  -- Utid of thread holding the lock.
157  blocked_utid JOINID(thread.id),
158  -- Thread name of thread holding the lock.
159  blocked_thread_name STRING,
160  -- Utid of thread holding the lock.
161  blocking_utid JOINID(thread.id),
162  -- Thread name of thread holding the lock.
163  blocking_thread_name STRING,
164  -- Tid of thread holding the lock.
165  blocking_tid LONG,
166  -- Upid of process experiencing lock contention.
167  upid JOINID(process.id),
168  -- Process name of process experiencing lock contention.
169  process_name STRING,
170  -- Slice id of lock contention.
171  id LONG,
172  -- Timestamp of lock contention start.
173  ts TIMESTAMP,
174  -- Wall clock duration of lock contention.
175  dur DURATION,
176  -- Monotonic clock duration of lock contention.
177  monotonic_dur DURATION,
178  -- Thread track id of blocked thread.
179  track_id JOINID(track.id),
180  -- Whether the blocked thread is the main thread.
181  is_blocked_thread_main LONG,
182  -- Tid of the blocked thread
183  blocked_thread_tid LONG,
184  -- Whether the blocking thread is the main thread.
185  is_blocking_thread_main LONG,
186  -- Tid of thread holding the lock.
187  blocking_thread_tid LONG,
188  -- Slice id of binder reply slice if lock contention was part of a binder txn.
189  binder_reply_id LONG,
190  -- Timestamp of binder reply slice if lock contention was part of a binder txn.
191  binder_reply_ts TIMESTAMP,
192  -- Tid of binder reply slice if lock contention was part of a binder txn.
193  binder_reply_tid LONG,
194  -- Pid of process experiencing lock contention.
195  pid LONG
196) AS
197SELECT
198  android_extract_android_monitor_contention_blocking_method(slice.name) AS blocking_method,
199  android_extract_android_monitor_contention_blocked_method(slice.name) AS blocked_method,
200  android_extract_android_monitor_contention_short_blocking_method(slice.name) AS short_blocking_method,
201  android_extract_android_monitor_contention_short_blocked_method(slice.name) AS short_blocked_method,
202  android_extract_android_monitor_contention_blocking_src(slice.name) AS blocking_src,
203  android_extract_android_monitor_contention_blocked_src(slice.name) AS blocked_src,
204  android_extract_android_monitor_contention_waiter_count(slice.name) AS waiter_count,
205  thread.utid AS blocked_utid,
206  thread.name AS blocked_thread_name,
207  blocking_thread.utid AS blocking_utid,
208  android_extract_android_monitor_contention_blocking_thread(slice.name) AS blocking_thread_name,
209  android_extract_android_monitor_contention_blocking_tid(slice.name) AS blocking_tid,
210  thread.upid AS upid,
211  process.name AS process_name,
212  slice.id,
213  slice.ts,
214  slice.dur,
215  _extract_duration_without_suspend(slice.ts, slice.dur) AS monotonic_dur,
216  slice.track_id,
217  thread.is_main_thread AS is_blocked_thread_main,
218  thread.tid AS blocked_thread_tid,
219  blocking_thread.is_main_thread AS is_blocking_thread_main,
220  blocking_thread.tid AS blocking_thread_tid,
221  binder_reply.id AS binder_reply_id,
222  binder_reply.ts AS binder_reply_ts,
223  binder_reply_thread.tid AS binder_reply_tid,
224  process.pid
225FROM slice
226JOIN thread_track
227  ON thread_track.id = slice.track_id
228LEFT JOIN thread
229  USING (utid)
230LEFT JOIN process
231  USING (upid)
232LEFT JOIN ancestor_slice(slice.id) AS binder_reply
233  ON binder_reply.name = 'binder reply'
234LEFT JOIN thread_track AS binder_reply_thread_track
235  ON binder_reply.track_id = binder_reply_thread_track.id
236LEFT JOIN thread AS binder_reply_thread
237  ON binder_reply_thread_track.utid = binder_reply_thread.utid
238-- Before Android U, we didn't have blocking_thread tid (aosp/3000578). We do a LEFT JOIN instead
239-- of JOIN so that on older devices we can at least capture the list of contentions without edges.
240LEFT JOIN thread AS blocking_thread
241  ON blocking_thread.tid = blocking_tid AND blocking_thread.upid = thread.upid
242JOIN _valid_android_monitor_contention
243  ON _valid_android_monitor_contention.id = slice.id
244WHERE
245  slice.name GLOB 'monitor contention*'
246  AND slice.dur != -1
247  AND NOT short_blocking_method IS NULL AND short_blocked_method IS NOT NULL
248GROUP BY
249  slice.id;
250
251CREATE PERFETTO INDEX _android_monitor_contention_blocking_utid_idx ON android_monitor_contention(blocking_utid, ts);
252
253CREATE PERFETTO INDEX _android_monitor_contention_id_idx ON android_monitor_contention(id);
254
255-- Monitor contention slices that are blocked by another monitor contention slice.
256-- They will have a |parent_id| field which is the id of the slice they are blocked by.
257CREATE PERFETTO TABLE _children AS
258SELECT
259  parent.id AS parent_id,
260  child.*
261FROM android_monitor_contention AS child
262JOIN android_monitor_contention AS parent
263  ON parent.blocked_utid = child.blocking_utid
264  AND child.ts BETWEEN parent.ts AND parent.ts + parent.dur;
265
266-- Monitor contention slices that are blocking another monitor contention slice.
267-- They will have a |child_id| field which is the id of the slice they are blocking.
268CREATE PERFETTO TABLE _parents AS
269SELECT
270  parent.*,
271  child.id AS child_id
272FROM android_monitor_contention AS parent
273JOIN android_monitor_contention AS child
274  ON parent.blocked_utid = child.blocking_utid
275  AND child.ts BETWEEN parent.ts AND parent.ts + parent.dur;
276
277-- Monitor contention slices that are neither blocking nor blocked by another monitor contention
278-- slice. They neither have |parent_id| nor |child_id| fields.
279CREATE PERFETTO TABLE _isolated AS
280WITH
281  parents_and_children AS (
282    SELECT
283      id
284    FROM _children
285    UNION ALL
286    SELECT
287      id
288    FROM _parents
289  ),
290  isolated AS (
291    SELECT
292      id
293    FROM android_monitor_contention
294    EXCEPT
295    SELECT
296      id
297    FROM parents_and_children
298  )
299SELECT
300  *
301FROM android_monitor_contention
302JOIN isolated
303  USING (id);
304
305-- Contains parsed monitor contention slices with the parent-child relationships.
306CREATE PERFETTO TABLE android_monitor_contention_chain (
307  -- Id of monitor contention slice blocking this contention.
308  parent_id LONG,
309  -- Name of the method holding the lock.
310  blocking_method STRING,
311  -- Blocked_method without arguments and return types.
312  blocked_method STRING,
313  -- Blocking_method without arguments and return types.
314  short_blocking_method STRING,
315  -- Blocked_method without arguments and return types.
316  short_blocked_method STRING,
317  -- File location of blocking_method in form <filename:linenumber>.
318  blocking_src STRING,
319  -- File location of blocked_method in form <filename:linenumber>.
320  blocked_src STRING,
321  -- Zero indexed number of threads trying to acquire the lock.
322  waiter_count LONG,
323  -- Utid of thread holding the lock.
324  blocked_utid JOINID(thread.id),
325  -- Thread name of thread holding the lock.
326  blocked_thread_name STRING,
327  -- Utid of thread holding the lock.
328  blocking_utid JOINID(thread.id),
329  -- Thread name of thread holding the lock.
330  blocking_thread_name STRING,
331  -- Tid of thread holding the lock.
332  blocking_tid LONG,
333  -- Upid of process experiencing lock contention.
334  upid JOINID(process.id),
335  -- Process name of process experiencing lock contention.
336  process_name STRING,
337  -- Slice id of lock contention.
338  id LONG,
339  -- Timestamp of lock contention start.
340  ts TIMESTAMP,
341  -- Wall clock duration of lock contention.
342  dur DURATION,
343  -- Monotonic clock duration of lock contention.
344  monotonic_dur DURATION,
345  -- Thread track id of blocked thread.
346  track_id JOINID(track.id),
347  -- Whether the blocked thread is the main thread.
348  is_blocked_thread_main LONG,
349  -- Tid of the blocked thread
350  blocked_thread_tid LONG,
351  -- Whether the blocking thread is the main thread.
352  is_blocking_thread_main LONG,
353  -- Tid of thread holding the lock.
354  blocking_thread_tid LONG,
355  -- Slice id of binder reply slice if lock contention was part of a binder txn.
356  binder_reply_id LONG,
357  -- Timestamp of binder reply slice if lock contention was part of a binder txn.
358  binder_reply_ts TIMESTAMP,
359  -- Tid of binder reply slice if lock contention was part of a binder txn.
360  binder_reply_tid LONG,
361  -- Pid of process experiencing lock contention.
362  pid LONG,
363  -- Id of monitor contention slice blocked by this contention.
364  child_id LONG
365) AS
366SELECT
367  NULL AS parent_id,
368  *,
369  NULL AS child_id
370FROM _isolated
371UNION ALL
372SELECT
373  c.*,
374  p.child_id
375FROM _children AS c
376LEFT JOIN _parents AS p
377  USING (id)
378UNION
379SELECT
380  c.parent_id,
381  p.*
382FROM _parents AS p
383LEFT JOIN _children AS c
384  USING (id);
385
386CREATE PERFETTO INDEX _android_monitor_contention_chain_idx ON android_monitor_contention_chain(blocking_method, blocking_utid, ts);
387
388-- First blocked node on a lock, i.e nodes with |waiter_count| = 0. The |dur| here is adjusted
389-- to only account for the time between the first thread waiting and the first thread to acquire
390-- the lock. That way, the thread state span joins below only compute the thread states where
391-- the blocking thread is actually holding the lock. This avoids counting the time when another
392-- waiter acquired the lock before the first waiter.
393CREATE PERFETTO VIEW _first_blocked_contention AS
394SELECT
395  start.id,
396  start.blocking_utid,
397  start.ts,
398  min(end.ts + end.dur) - start.ts AS dur
399FROM android_monitor_contention_chain AS start
400JOIN android_monitor_contention_chain AS end
401  ON start.blocking_utid = end.blocking_utid
402  AND start.blocking_method = end.blocking_method
403  AND end.ts BETWEEN start.ts AND start.ts + start.dur
404WHERE
405  start.waiter_count = 0
406GROUP BY
407  start.id;
408
409CREATE PERFETTO VIEW _blocking_thread_state AS
410SELECT
411  utid AS blocking_utid,
412  ts,
413  dur,
414  state,
415  blocked_function
416FROM thread_state;
417
418CREATE VIRTUAL TABLE _android_monitor_contention_chain_thread_state USING SPAN_JOIN (_first_blocked_contention PARTITIONED blocking_utid,
419            _blocking_thread_state PARTITIONED blocking_utid);
420
421-- Contains the span join of the first waiters in the |android_monitor_contention_chain| with their
422-- blocking_thread thread state.
423--
424-- Note that we only span join the duration where the lock was actually held and contended.
425-- This can be less than the duration the lock was 'waited on' when a different waiter acquired the
426-- lock earlier than the first waiter.
427CREATE PERFETTO TABLE android_monitor_contention_chain_thread_state (
428  -- Slice id of lock contention.
429  id LONG,
430  -- Timestamp of lock contention start.
431  ts TIMESTAMP,
432  -- Wall clock duration of lock contention.
433  dur DURATION,
434  -- Utid of the blocking |thread_state|.
435  blocking_utid JOINID(thread.id),
436  -- Blocked kernel function of the blocking thread.
437  blocked_function STRING,
438  -- Thread state of the blocking thread.
439  state STRING
440) AS
441SELECT
442  id,
443  ts,
444  dur,
445  blocking_utid,
446  blocked_function,
447  state
448FROM _android_monitor_contention_chain_thread_state;
449
450-- Aggregated thread_states on the 'blocking thread', the thread holding the lock.
451-- This builds on the data from |android_monitor_contention_chain| and
452-- for each contention slice, it returns the aggregated sum of all the thread states on the
453-- blocking thread.
454--
455-- Note that this data is only available for the first waiter on a lock.
456--
457CREATE PERFETTO VIEW android_monitor_contention_chain_thread_state_by_txn (
458  -- Slice id of the monitor contention.
459  id LONG,
460  -- A |thread_state| that occurred in the blocking thread during the contention.
461  thread_state STRING,
462  -- Total time the blocking thread spent in the |thread_state| during contention.
463  thread_state_dur DURATION,
464  -- Count of all times the blocking thread entered |thread_state| during the contention.
465  thread_state_count LONG
466) AS
467SELECT
468  id,
469  state AS thread_state,
470  sum(dur) AS thread_state_dur,
471  count(dur) AS thread_state_count
472FROM android_monitor_contention_chain_thread_state
473GROUP BY
474  id,
475  thread_state;
476
477-- Aggregated blocked_functions on the 'blocking thread', the thread holding the lock.
478-- This builds on the data from |android_monitor_contention_chain| and
479-- for each contention, it returns the aggregated sum of all the kernel
480-- blocked function durations on the blocking thread.
481--
482-- Note that this data is only available for the first waiter on a lock.
483CREATE PERFETTO VIEW android_monitor_contention_chain_blocked_functions_by_txn (
484  -- Slice id of the monitor contention.
485  id LONG,
486  -- Blocked kernel function in a thread state in the blocking thread during the contention.
487  blocked_function STRING,
488  -- Total time the blocking thread spent in the |blocked_function| during the contention.
489  blocked_function_dur DURATION,
490  -- Count of all times the blocking thread executed the |blocked_function| during the contention.
491  blocked_function_count LONG
492) AS
493SELECT
494  id,
495  blocked_function,
496  sum(dur) AS blocked_function_dur,
497  count(dur) AS blocked_function_count
498FROM android_monitor_contention_chain_thread_state
499WHERE
500  blocked_function IS NOT NULL
501GROUP BY
502  id,
503  blocked_function;
504
505-- Returns a DAG of all Java lock contentions in a process.
506-- Each node in the graph is a <thread:Java method> pair.
507-- Each edge connects from a node waiting on a lock to a node holding a lock.
508-- The weights of each node represent the cumulative wall time the node blocked
509-- other nodes connected to it.
510CREATE PERFETTO FUNCTION android_monitor_contention_graph(
511    -- Upid of process to generate a lock graph for.
512    upid JOINID(process.id)
513)
514RETURNS TABLE (
515  -- Pprof of lock graph.
516  pprof BYTES
517) AS
518WITH
519  contention_chain AS (
520    SELECT
521      *,
522      iif(blocked_thread_name GLOB 'binder:*', 'binder', blocked_thread_name) AS blocked_thread_name_norm,
523      iif(blocking_thread_name GLOB 'binder:*', 'binder', blocking_thread_name) AS blocking_thread_name_norm
524    FROM android_monitor_contention_chain
525    WHERE
526      upid = $upid
527    GROUP BY
528      id,
529      parent_id
530  ),
531  graph AS (
532    SELECT
533      id,
534      dur,
535      cat_stacks(
536        blocked_thread_name_norm || ':' || short_blocked_method,
537        blocking_thread_name_norm || ':' || short_blocking_method
538      ) AS stack
539    FROM contention_chain
540    WHERE
541      parent_id IS NULL
542    UNION ALL
543    SELECT
544      c.id,
545      c.dur AS dur,
546      cat_stacks(
547        blocked_thread_name_norm || ':' || short_blocked_method,
548        blocking_thread_name_norm || ':' || short_blocking_method,
549        stack
550      ) AS stack
551    FROM contention_chain AS c, graph AS p
552    WHERE
553      p.id = c.parent_id
554  )
555SELECT
556  experimental_profile(stack, 'duration', 'ns', dur) AS pprof
557FROM graph;
558