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