| -- |
| -- Copyright 2022 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. |
| -- |
| |
| SELECT IMPORT('common.timestamps'); |
| |
| -- Count Binder transactions per process. |
| -- |
| -- @column process_name Name of the process that started the binder transaction. |
| -- @column pid PID of the process that started the binder transaction. |
| -- @column slice_name Name of the slice with binder transaction. |
| -- @column event_count Number of binder transactions in process in slice. |
| CREATE VIEW android_binder_metrics_by_process AS |
| SELECT |
| process.name AS process_name, |
| process.pid AS pid, |
| slice.name AS slice_name, |
| COUNT(*) AS event_count |
| FROM slice |
| JOIN thread_track ON slice.track_id = thread_track.id |
| JOIN thread ON thread.utid = thread_track.utid |
| JOIN process ON thread.upid = process.upid |
| WHERE |
| slice.name GLOB 'binder*' |
| GROUP BY |
| process_name, |
| slice_name; |
| |
| -- Breakdown synchronous binder transactions per txn. |
| -- It returns data about the client and server ends of every binder transaction. |
| -- |
| -- @column aidl_name name of the binder interface if existing |
| -- @column binder_txn_id slice id of the binder txn |
| -- @column client_process name of the client process |
| -- @column client_thread name of the client thread |
| -- @column client_upid name of the client upid |
| -- @column client_utid name of the client utid |
| -- @column client_ts timestamp of the client txn |
| -- @column client_dur dur of the client txn |
| -- @column is_main_thread Whether the txn was initiated from the main thread of the client process |
| -- @column binder_reply_id slice id of the binder reply |
| -- @column server_process name of the server process |
| -- @column server_thread name of the server thread |
| -- @column server_upid name of the server upid |
| -- @column server_utid name of the server utid |
| -- @column server_ts timestamp of the server txn |
| -- @column server_dur dur of the server txn |
| CREATE VIEW android_sync_binder_metrics_by_txn AS |
| WITH |
| -- Fetch the broken binder txns first, i.e, the txns that have children slices |
| -- They are definietly broken because synchronous txns are blocked sleeping while |
| -- waiting for a response. |
| -- These broken txns will be excluded below in the binder_txn CTE |
| broken_binder_txn AS ( |
| SELECT ancestor.id FROM slice |
| JOIN slice ancestor ON ancestor.id = slice.parent_id |
| WHERE ancestor.name = 'binder transaction' |
| GROUP BY ancestor.id |
| ), |
| -- Adding MATERIALIZED here matters in cases where there are few/no binder |
| -- transactions in the trace. Our cost estimation is not good enough to allow |
| -- the query planner to see through to this fact. Instead, our cost estimation |
| -- causes repeated queries on this table which is slow because it's an O(n) |
| -- query. |
| -- |
| -- We should fix this by doing some (ideally all) of the following: |
| -- 1) Add support for columnar tables in SQL which will allow for |
| -- "subsetting" the slice table to only contain binder transactions. |
| -- 2) Make this query faster by adding improving string filtering. |
| -- 3) Add caching so that even if these queries happen many times, they are |
| -- fast. |
| -- 4) Improve cost estimation algorithm to allow the joins to happen the |
| -- right way around. |
| binder_txn AS MATERIALIZED ( |
| SELECT |
| slice.id AS binder_txn_id, |
| process.name AS process_name, |
| thread.name AS thread_name, |
| thread.utid AS utid, |
| thread.tid AS tid, |
| process.pid AS pid, |
| process.upid AS upid, |
| slice.ts, |
| slice.dur, |
| thread.is_main_thread |
| FROM slice |
| JOIN thread_track ON slice.track_id = thread_track.id |
| JOIN thread USING (utid) |
| JOIN process USING (upid) |
| LEFT JOIN broken_binder_txn ON broken_binder_txn.id = slice.id |
| WHERE slice.name = 'binder transaction' |
| AND broken_binder_txn.id IS NULL |
| ), |
| binder_reply AS ( |
| SELECT |
| binder_txn.*, |
| binder_reply.ts AS server_ts, |
| binder_reply.dur AS server_dur, |
| binder_reply.id AS binder_reply_id, |
| reply_thread.name AS server_thread, |
| reply_process.name AS server_process, |
| reply_thread.utid AS server_utid, |
| reply_thread.tid AS server_tid, |
| reply_process.pid AS server_pid, |
| reply_process.upid AS server_upid, |
| aidl.name AS aidl_name |
| FROM binder_txn |
| JOIN flow binder_flow ON binder_txn.binder_txn_id = binder_flow.slice_out |
| JOIN slice binder_reply ON binder_flow.slice_in = binder_reply.id |
| JOIN thread_track reply_thread_track |
| ON binder_reply.track_id = reply_thread_track.id |
| JOIN thread reply_thread ON reply_thread.utid = reply_thread_track.utid |
| JOIN process reply_process ON reply_process.upid = reply_thread.upid |
| LEFT JOIN slice aidl ON aidl.parent_id = binder_reply.id |
| AND (aidl.name GLOB 'AIDL::cpp*Server' |
| OR aidl.name GLOB 'AIDL::java*server' |
| OR aidl.name GLOB 'HIDL::*server') |
| ) |
| SELECT |
| MIN(aidl_name) AS aidl_name, |
| binder_txn_id, |
| process_name AS client_process, |
| thread_name AS client_thread, |
| upid AS client_upid, |
| utid AS client_utid, |
| tid AS client_tid, |
| pid AS client_pid, |
| is_main_thread, |
| ts AS client_ts, |
| dur AS client_dur, |
| binder_reply_id, |
| server_process, |
| server_thread, |
| server_upid, |
| server_utid, |
| server_tid, |
| server_pid, |
| server_ts, |
| server_dur |
| FROM binder_reply |
| WHERE client_dur != -1 AND server_dur != -1 AND client_dur >= server_dur |
| GROUP BY |
| process_name, |
| thread_name, |
| binder_txn_id, |
| binder_reply_id; |
| |
| CREATE VIEW internal_binder_txn |
| AS |
| SELECT client_ts AS ts, client_dur AS dur, client_utid AS utid, * |
| FROM android_sync_binder_metrics_by_txn; |
| |
| CREATE VIEW internal_binder_reply |
| AS |
| SELECT server_ts AS ts, server_dur AS dur, server_utid AS utid, * |
| FROM android_sync_binder_metrics_by_txn; |
| |
| CREATE VIRTUAL TABLE internal_sp_binder_txn_thread_state |
| USING |
| SPAN_JOIN(internal_binder_txn PARTITIONED utid, thread_state PARTITIONED utid); |
| |
| CREATE VIRTUAL TABLE internal_sp_binder_reply_thread_state |
| USING |
| SPAN_JOIN(internal_binder_reply PARTITIONED utid, thread_state PARTITIONED utid); |
| |
| -- Aggregated thread_states on the client and server side per binder txn |
| -- This builds on the data from |android_sync_binder_metrics_by_txn| and |
| -- for each end (client and server) of the transaction, it returns |
| -- the aggregated sum of all the thread state durations. |
| -- The |thread_state_type| column represents whether a given 'aggregated thread_state' |
| -- row is on the client or server side. 'binder_txn' is client side and 'binder_reply' |
| -- is server side. |
| -- |
| -- @column binder_txn_id slice id of the binder txn |
| -- @column binder_reply_id slice id of the binder reply |
| -- @column thread_state_type whether thread state is on the txn or reply side |
| -- @column thread_state a thread_state that occurred in the txn |
| -- @column thread_state_dur aggregated dur of the |thread_state| in the txn |
| -- @column thread_state_count aggregated count of the |thread_state| in the txn |
| CREATE VIEW android_sync_binder_thread_state_by_txn |
| AS |
| SELECT |
| binder_txn_id, |
| client_ts, |
| client_tid, |
| binder_reply_id, |
| server_ts, |
| server_tid, |
| 'binder_txn' AS thread_state_type, |
| state AS thread_state, |
| SUM(dur) AS thread_state_dur, |
| COUNT(dur) AS thread_state_count |
| FROM internal_sp_binder_txn_thread_state |
| GROUP BY binder_txn_id, binder_reply_id, thread_state_type, thread_state |
| UNION ALL |
| SELECT |
| binder_txn_id, |
| client_ts, |
| client_tid, |
| binder_reply_id, |
| server_ts, |
| server_tid, |
| 'binder_reply' AS thread_state_type, |
| state AS thread_state, |
| SUM(dur) AS thread_state_dur, |
| COUNT(dur) AS thread_state_count |
| FROM internal_sp_binder_reply_thread_state |
| GROUP BY binder_txn_id, binder_reply_id, thread_state_type, thread_state; |
| |
| -- Aggregated blocked_functions on the client and server side per binder txn |
| -- This builds on the data from |android_sync_binder_metrics_by_txn| and |
| -- for each end (client and server) of the transaction, it returns |
| -- the aggregated sum of all the kernel blocked function durations. |
| -- The |thread_state_type| column represents whether a given 'aggregated blocked_function' |
| -- row is on the client or server side. 'binder_txn' is client side and 'binder_reply' |
| -- is server side. |
| -- |
| -- @column binder_txn_id slice id of the binder txn |
| -- @column binder_reply_id slice id of the binder reply |
| -- @column thread_state_type whether thread state is on the txn or reply side |
| -- @column blocked_function blocked kernel function in a thread state |
| -- @column blocked_function_dur aggregated dur of the |blocked_function| in the txn |
| -- @column blocked_function_count aggregated count of the |blocked_function| in the txn |
| CREATE VIEW android_sync_binder_blocked_functions_by_txn |
| AS |
| SELECT |
| binder_txn_id, |
| client_ts, |
| client_tid, |
| binder_reply_id, |
| server_ts, |
| server_tid, |
| 'binder_txn' AS thread_state_type, |
| blocked_function, |
| SUM(dur) AS blocked_function_dur, |
| COUNT(dur) AS blocked_function_count |
| FROM internal_sp_binder_txn_thread_state |
| WHERE blocked_function IS NOT NULL |
| GROUP BY binder_txn_id, binder_reply_id, blocked_function |
| UNION ALL |
| SELECT |
| binder_txn_id, |
| client_ts, |
| client_tid, |
| binder_reply_id, |
| server_ts, |
| server_tid, |
| 'binder_reply' AS thread_state_type, |
| blocked_function, |
| SUM(dur) AS blocked_function_dur, |
| COUNT(dur) AS blocked_function_count |
| FROM internal_sp_binder_reply_thread_state |
| WHERE blocked_function IS NOT NULL |
| GROUP BY binder_txn_id, binder_reply_id, blocked_function; |