-- -- Copyright 2023 The Android Open Source Project -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- https://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Extracts the blocking thread from a slice name -- -- @arg slice_name STRING Name of slice -- @ret STRING Blocking thread SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_THREAD(slice_name STRING)', 'STRING', ' SELECT STR_SPLIT(STR_SPLIT($slice_name, "with owner ", 1), " (", 0) ' ); -- Extracts the blocking thread tid from a slice name -- -- @arg slice_name STRING Name of slice -- @ret INT Blocking thread tid SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_TID(slice_name STRING)', 'INT', ' SELECT CAST(STR_SPLIT(STR_SPLIT($slice_name, " (", 1), ")", 0) AS INT) ' ); -- Extracts the blocking method from a slice name -- -- @arg slice_name STRING Name of slice -- @ret STRING Blocking thread SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_METHOD(slice_name STRING)', 'STRING', ' SELECT STR_SPLIT(STR_SPLIT($slice_name, ") at ", 1), "(", 0) || "(" || STR_SPLIT(STR_SPLIT($slice_name, ") at ", 1), "(", 1) ' ); -- Extracts a shortened form of the blocking method name from a slice name. -- The shortened form discards the parameter and return -- types. -- -- @arg slice_name STRING Name of slice -- @ret STRING Blocking thread SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKING_METHOD(slice_name STRING)', 'STRING', ' SELECT STR_SPLIT(STR_SPLIT(ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_METHOD($slice_name), " ", 1), "(", 0) ' ); -- Extracts the monitor contention blocked method from a slice name -- -- @arg slice_name STRING Name of slice -- @ret STRING Blocking thread SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_METHOD(slice_name STRING)', 'STRING', ' SELECT STR_SPLIT(STR_SPLIT($slice_name, "blocking from ", 1), "(", 0) || "(" || STR_SPLIT(STR_SPLIT($slice_name, "blocking from ", 1), "(", 1) ' ); -- Extracts a shortened form of the monitor contention blocked method name -- from a slice name. The shortened form discards the parameter and return -- types. -- -- @arg slice_name STRING Name of slice -- @ret STRING Blocking thread SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKED_METHOD(slice_name STRING)', 'STRING', ' SELECT STR_SPLIT(STR_SPLIT(ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_METHOD($slice_name), " ", 1), "(", 0) ' ); -- Extracts the number of waiters on the monitor from a slice name -- -- @arg slice_name STRING Name of slice -- @ret INT Count of waiters on the lock SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_WAITER_COUNT(slice_name STRING)', 'INT', ' SELECT CAST(STR_SPLIT(STR_SPLIT($slice_name, "waiters=", 1), " ", 0) AS INT) ' ); -- Extracts the monitor contention blocking source location from a slice name -- -- @arg slice_name STRING Name of slice -- @ret STRING Blocking thread SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_SRC(slice_name STRING)', 'STRING', ' SELECT STR_SPLIT(STR_SPLIT($slice_name, ")(", 1), ")", 0) ' ); -- Extracts the monitor contention blocked source location from a slice name -- -- @arg slice_name STRING Name of slice -- @ret STRING Blocking thread SELECT CREATE_FUNCTION( 'ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_SRC(slice_name STRING)', 'STRING', ' SELECT STR_SPLIT(STR_SPLIT($slice_name, ")(", 2), ")", 0) ' ); CREATE TABLE internal_broken_android_monitor_contention AS SELECT ancestor.parent_id AS id FROM slice JOIN slice ancestor ON ancestor.id = slice.parent_id WHERE ancestor.name LIKE 'Lock contention on a monitor lock%' GROUP BY ancestor.id; -- Contains parsed monitor contention slices. -- -- @column blocking_method Name of the method holding the lock. -- @column blocked_methhod Name of the method trying to acquire the lock. -- @column short_blocking_method Blocking_method without arguments and return types. -- @column short_blocked_method Blocked_method without arguments and return types. -- @column blocking_src File location of blocking_method in form . -- @column blocked_src File location of blocked_method in form . -- @column waiter_count Zero indexed number of threads trying to acquire the lock. -- @column blocking_utid Utid of thread holding the lock. -- @column blocking_thread_name Thread name of thread holding the lock. -- @column upid Upid of process experiencing lock contention. -- @column process_name Process name of process experiencing lock contention. -- @column id Slice id of lock contention. -- @column ts Timestamp of lock contention start. -- @column dur Duration of lock contention. -- @column track_id Thread track id of blocked thread. -- @column is_blocked_main_thread Whether the blocked thread is the main thread. -- @column is_blocking_main_thread Whether the blocking thread is the main thread. -- @column binder_reply_id Slice id of binder reply slice if lock contention was part of a binder txn. -- @column binder_reply_ts Timestamp of binder reply slice if lock contention was part of a binder txn. -- @column binder_reply_tid Tid of binder reply slice if lock contention was part of a binder txn. CREATE TABLE android_monitor_contention AS SELECT ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_METHOD(slice.name) AS blocking_method, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_METHOD(slice.name) AS blocked_method, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKING_METHOD(slice.name) AS short_blocking_method, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_SHORT_BLOCKED_METHOD(slice.name) AS short_blocked_method, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_SRC(slice.name) AS blocking_src, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKED_SRC(slice.name) AS blocked_src, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_WAITER_COUNT(slice.name) AS waiter_count, thread.utid AS blocked_utid, thread.name AS blocked_thread_name, blocking_thread.utid AS blocking_utid, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_THREAD(slice.name) AS blocking_thread_name, ANDROID_EXTRACT_ANDROID_MONITOR_CONTENTION_BLOCKING_TID(slice.name) AS blocking_tid, thread.upid AS upid, process.name AS process_name, slice.id, slice.ts, slice.dur, slice.track_id, thread.is_main_thread AS is_blocked_thread_main, thread.tid AS blocked_thread_tid, blocking_thread.is_main_thread AS is_blocking_thread_main, blocking_thread.tid AS blocking_thread_tid, binder_reply.id AS binder_reply_id, binder_reply.ts AS binder_reply_ts, binder_reply_thread.tid AS binder_reply_tid, process.pid FROM slice JOIN thread_track ON thread_track.id = slice.track_id LEFT JOIN thread USING (utid) LEFT JOIN process USING (upid) LEFT JOIN internal_broken_android_monitor_contention ON internal_broken_android_monitor_contention.id = slice.id LEFT JOIN ANCESTOR_SLICE(slice.id) binder_reply ON binder_reply.name = 'binder reply' LEFT JOIN thread_track binder_reply_thread_track ON binder_reply.track_id = binder_reply_thread_track.id LEFT JOIN thread binder_reply_thread ON binder_reply_thread_track.utid = binder_reply_thread.utid JOIN thread blocking_thread ON blocking_thread.tid = blocking_tid AND blocking_thread.upid = thread.upid WHERE slice.name LIKE 'monitor contention%' AND slice.dur != -1 AND internal_broken_android_monitor_contention.id IS NULL AND short_blocking_method IS NOT NULL AND short_blocked_method IS NOT NULL GROUP BY slice.id; -- Contains parsed monitor contention slices with the parent-child relationships. -- -- @column parent_id Id of slice blocking the blocking_thread. -- @column blocking_method Name of the method holding the lock. -- @column blocked_methhod Name of the method trying to acquire the lock. -- @column short_blocking_method Blocking_method without arguments and return types. -- @column short_blocked_method Blocked_method without arguments and return types. -- @column blocking_src File location of blocking_method in form . -- @column blocked_src File location of blocked_method in form . -- @column waiter_count Zero indexed number of threads trying to acquire the lock. -- @column blocking_utid Utid of thread holding the lock. -- @column blocking_thread_name Thread name of thread holding the lock. -- @column upid Upid of process experiencing lock contention. -- @column process_name Process name of process experiencing lock contention. -- @column id Slice id of lock contention. -- @column ts Timestamp of lock contention start. -- @column dur Duration of lock contention. -- @column track_id Thread track id of blocked thread. -- @column is_blocked_main_thread Whether the blocked thread is the main thread. -- @column is_blocking_main_thread Whether the blocking thread is the main thread. -- @column binder_reply_id Slice id of binder reply slice if lock contention was part of a binder txn. -- @column binder_reply_ts Timestamp of binder reply slice if lock contention was part of a binder txn. -- @column binder_reply_tid Tid of binder reply slice if lock contention was part of a binder txn. CREATE TABLE android_monitor_contention_chain AS SELECT parent.id AS parent_id, child.* FROM android_monitor_contention child LEFT JOIN android_monitor_contention parent ON child.blocked_utid = parent.blocking_utid AND parent.ts BETWEEN child.ts AND child.ts + child.dur; CREATE VIEW internal_blocking_thread_state AS SELECT utid AS blocking_utid, ts, dur, state, blocked_function FROM thread_state; -- Contains the span join of the |android_monitor_contention_chain| with their -- blocking thread thread state. -- -- @column parent_id Id of slice blocking the blocking_thread. -- @column blocking_method Name of the method holding the lock. -- @column blocked_methhod Name of the method trying to acquire the lock. -- @column short_blocking_method Blocking_method without arguments and return types. -- @column short_blocked_method Blocked_method without arguments and return types. -- @column blocking_src File location of blocking_method in form . -- @column blocked_src File location of blocked_method in form . -- @column waiter_count Zero indexed number of threads trying to acquire the lock. -- @column blocking_utid Utid of thread holding the lock. -- @column blocking_thread_name Thread name of thread holding the lock. -- @column upid Upid of process experiencing lock contention. -- @column process_name Process name of process experiencing lock contention. -- @column id Slice id of lock contention. -- @column ts Timestamp of lock contention start. -- @column dur Duration of lock contention. -- @column track_id Thread track id of blocked thread. -- @column is_blocked_main_thread Whether the blocked thread is the main thread. -- @column is_blocking_main_thread Whether the blocking thread is the main thread. -- @column binder_reply_id Slice id of binder reply slice if lock contention was part of a binder txn. -- @column binder_reply_ts Timestamp of binder reply slice if lock contention was part of a binder txn. -- @column binder_reply_tid Tid of binder reply slice if lock contention was part of a binder txn. -- @column blocking_utid Utid of the blocking |thread_state|. -- @column ts Timestamp of the blocking |thread_state|. -- @column state Thread state of the blocking thread. -- @column blocked_function Blocked kernel function of the blocking thread. CREATE VIRTUAL TABLE android_monitor_contention_chain_thread_state USING SPAN_JOIN(android_monitor_contention_chain PARTITIONED blocking_utid, internal_blocking_thread_state PARTITIONED blocking_utid); -- Aggregated blocked_functions on the 'blocking thread', the thread holding the lock. -- This builds on the data from |android_monitor_contention_chain| and -- for each contention slice, it returns the aggregated sum of all the thread states on the -- blocking thread. -- -- @column id Slice id of the monitor contention. -- @column thread_state A |thread_state| that occurred in the blocking thread during the contention. -- @column thread_state_dur Total time the blocking thread spent in the |thread_state| during -- contention. -- @column thread_state_count Count of all times the blocking thread entered |thread_state| during -- the contention. CREATE VIEW android_monitor_contention_chain_thread_state_by_txn AS SELECT id, state AS thread_state, SUM(dur) AS thread_state_dur, COUNT(dur) AS thread_state_count FROM android_monitor_contention_chain_thread_state GROUP BY id, thread_state; -- Aggregated blocked_functions on the 'blocking thread', the thread holding the lock. -- This builds on the data from |android_monitor_contention_chain| and -- for each contention, it returns the aggregated sum of all the kernel -- blocked function durations on the blocking thread. -- -- @column id Slice id of the monitor contention. -- @column blocked_function Blocked kernel function in a thread state in the blocking thread during -- the contention. -- @column blocked_function_dur Total time the blocking thread spent in the |blocked_function| -- during the contention. -- @column blocked_function_count Count of all times the blocking thread executed the -- |blocked_function| during the contention. CREATE VIEW android_monitor_contention_chain_blocked_functions_by_txn AS SELECT id, blocked_function, SUM(dur) AS blocked_function_dur, COUNT(dur) AS blocked_function_count FROM android_monitor_contention_chain_thread_state WHERE blocked_function IS NOT NULL GROUP BY id, blocked_function;