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; 18 19INCLUDE PERFETTO MODULE android.suspend; 20 21INCLUDE PERFETTO MODULE slices.flow; 22 23-- Count Binder transactions per process. 24CREATE PERFETTO VIEW android_binder_metrics_by_process ( 25 -- Name of the process that started the binder transaction. 26 process_name STRING, 27 -- PID of the process that started the binder transaction. 28 pid LONG, 29 -- Name of the slice with binder transaction. 30 slice_name STRING, 31 -- Number of binder transactions in process in slice. 32 event_count LONG 33) AS 34SELECT 35 process.name AS process_name, 36 process.pid AS pid, 37 slice.name AS slice_name, 38 count(*) AS event_count 39FROM slice 40JOIN thread_track 41 ON slice.track_id = thread_track.id 42JOIN thread 43 ON thread.utid = thread_track.utid 44JOIN process 45 ON thread.upid = process.upid 46WHERE 47 slice.name GLOB 'binder*' 48GROUP BY 49 process_name, 50 slice_name; 51 52CREATE PERFETTO TABLE _binder_txn_merged AS 53WITH 54 maybe_broken_binder_txn AS ( 55 -- Fetch the broken binder txns first, i.e, the txns that have children slices 56 -- They may be broken because synchronous txns are typically blocked sleeping while 57 -- waiting for a response. 58 -- These broken txns will be excluded below in the binder_txn CTE 59 SELECT 60 ancestor.id 61 FROM slice 62 JOIN slice AS ancestor 63 ON ancestor.id = slice.parent_id 64 WHERE 65 ancestor.name = 'binder transaction' 66 GROUP BY 67 ancestor.id 68 ), 69 nested_binder_txn AS ( 70 -- Detect the non-broken cases which are just nested binder txns 71 SELECT DISTINCT 72 root_node_id AS id 73 FROM _slice_following_flow!(maybe_broken_binder_txn) 74 ), 75 broken_binder_txn AS ( 76 -- Exclude the nested txns from the 'maybe broken' set 77 SELECT 78 * 79 FROM maybe_broken_binder_txn 80 EXCEPT 81 SELECT 82 * 83 FROM nested_binder_txn 84 ), 85 -- Adding MATERIALIZED here matters in cases where there are few/no binder 86 -- transactions in the trace. Our cost estimation is not good enough to allow 87 -- the query planner to see through to this fact. Instead, our cost estimation 88 -- causes repeated queries on this table which is slow because it's an O(n) 89 -- query. 90 -- 91 -- We should fix this by doing some (ideally all) of the following: 92 -- 1) Add support for columnar tables in SQL which will allow for 93 -- "subsetting" the slice table to only contain binder transactions. 94 -- 2) Make this query faster by adding improving string filtering. 95 -- 3) Add caching so that even if these queries happen many times, they are 96 -- fast. 97 -- 4) Improve cost estimation algorithm to allow the joins to happen the 98 -- right way around. 99 binder_txn AS MATERIALIZED ( 100 SELECT 101 slice.id AS binder_txn_id, 102 process.name AS process_name, 103 thread.name AS thread_name, 104 thread.utid AS utid, 105 thread.tid AS tid, 106 process.pid AS pid, 107 process.upid AS upid, 108 slice.ts, 109 slice.dur, 110 thread.is_main_thread 111 FROM slice 112 JOIN thread_track 113 ON slice.track_id = thread_track.id 114 JOIN thread 115 USING (utid) 116 JOIN process 117 USING (upid) 118 LEFT JOIN broken_binder_txn 119 ON broken_binder_txn.id = slice.id 120 WHERE 121 slice.name = 'binder transaction' AND broken_binder_txn.id IS NULL 122 ), 123 binder_reply AS ( 124 SELECT 125 binder_txn.*, 126 binder_reply.ts AS server_ts, 127 binder_reply.dur AS server_dur, 128 binder_reply.id AS binder_reply_id, 129 reply_thread.name AS server_thread, 130 reply_process.name AS server_process, 131 reply_thread.utid AS server_utid, 132 reply_thread.tid AS server_tid, 133 reply_process.pid AS server_pid, 134 reply_process.upid AS server_upid, 135 aidl.name AS aidl_name, 136 aidl.ts AS aidl_ts, 137 aidl.dur AS aidl_dur 138 FROM binder_txn 139 JOIN flow AS binder_flow 140 ON binder_txn.binder_txn_id = binder_flow.slice_out 141 JOIN slice AS binder_reply 142 ON binder_flow.slice_in = binder_reply.id 143 JOIN thread_track AS reply_thread_track 144 ON binder_reply.track_id = reply_thread_track.id 145 JOIN thread AS reply_thread 146 ON reply_thread.utid = reply_thread_track.utid 147 JOIN process AS reply_process 148 ON reply_process.upid = reply_thread.upid 149 LEFT JOIN slice AS aidl 150 ON aidl.parent_id = binder_reply.id 151 AND ( 152 -- Filter for only server side AIDL slices as there are some client side ones for cpp 153 aidl.name GLOB 'AIDL::*Server' 154 OR aidl.name GLOB 'AIDL::*server' 155 OR aidl.name GLOB 'HIDL::*server' 156 ) 157 ) 158SELECT 159 min(aidl_name) AS aidl_name, 160 aidl_ts, 161 aidl_dur, 162 binder_txn_id, 163 process_name AS client_process, 164 thread_name AS client_thread, 165 upid AS client_upid, 166 utid AS client_utid, 167 tid AS client_tid, 168 pid AS client_pid, 169 is_main_thread, 170 ts AS client_ts, 171 dur AS client_dur, 172 binder_reply_id, 173 server_process, 174 server_thread, 175 server_upid, 176 server_utid, 177 server_tid, 178 server_pid, 179 server_ts, 180 server_dur 181FROM binder_reply 182WHERE 183 client_dur != -1 AND server_dur != -1 AND client_dur >= server_dur 184GROUP BY 185 process_name, 186 thread_name, 187 binder_txn_id, 188 binder_reply_id; 189 190CREATE PERFETTO TABLE _oom_score AS 191SELECT 192 process.upid, 193 cast_int!(c.value) AS value, 194 c.ts, 195 coalesce(lead(ts) OVER (PARTITION BY upid ORDER BY ts), trace_end()) AS end_ts 196FROM counter AS c 197JOIN process_counter_track AS t 198 ON c.track_id = t.id 199JOIN process 200 USING (upid) 201WHERE 202 t.name = 'oom_score_adj'; 203 204CREATE PERFETTO INDEX _oom_score_idx ON _oom_score(upid, ts); 205 206-- Breakdown synchronous binder transactions per txn. 207-- It returns data about the client and server ends of every binder transaction. 208CREATE PERFETTO VIEW _sync_binder_metrics_by_txn AS 209SELECT 210 binder.*, 211 client_oom.value AS client_oom_score, 212 server_oom.value AS server_oom_score 213FROM _binder_txn_merged AS binder 214LEFT JOIN _oom_score AS client_oom 215 ON binder.client_upid = client_oom.upid 216 AND binder.client_ts BETWEEN client_oom.ts AND client_oom.end_ts 217LEFT JOIN _oom_score AS server_oom 218 ON binder.server_upid = server_oom.upid 219 AND binder.server_ts BETWEEN server_oom.ts AND server_oom.end_ts; 220 221CREATE PERFETTO VIEW _binder_txn AS 222SELECT 223 client_ts AS ts, 224 client_dur AS dur, 225 client_utid AS utid, 226 * 227FROM _sync_binder_metrics_by_txn; 228 229CREATE PERFETTO VIEW _binder_reply AS 230SELECT 231 server_ts AS ts, 232 server_dur AS dur, 233 server_utid AS utid, 234 * 235FROM _sync_binder_metrics_by_txn; 236 237CREATE VIRTUAL TABLE _sp_binder_txn_thread_state USING SPAN_JOIN (_binder_txn PARTITIONED utid, thread_state PARTITIONED utid); 238 239CREATE VIRTUAL TABLE _sp_binder_reply_thread_state USING SPAN_JOIN (_binder_reply PARTITIONED utid, thread_state PARTITIONED utid); 240 241-- Aggregated thread_states on the client and server side per binder txn 242-- This builds on the data from |_sync_binder_metrics_by_txn| and 243-- for each end (client and server) of the transaction, it returns 244-- the aggregated sum of all the thread state durations. 245-- The |thread_state_type| column represents whether a given 'aggregated thread_state' 246-- row is on the client or server side. 'binder_txn' is client side and 'binder_reply' 247-- is server side. 248CREATE PERFETTO VIEW android_sync_binder_thread_state_by_txn ( 249 -- slice id of the binder txn 250 binder_txn_id LONG, 251 -- Client timestamp 252 client_ts TIMESTAMP, 253 -- Client tid 254 client_tid LONG, 255 -- slice id of the binder reply 256 binder_reply_id LONG, 257 -- Server timestamp 258 server_ts TIMESTAMP, 259 -- Server tid 260 server_tid LONG, 261 -- whether thread state is on the txn or reply side 262 thread_state_type STRING, 263 -- a thread_state that occurred in the txn 264 thread_state STRING, 265 -- aggregated dur of the |thread_state| in the txn 266 thread_state_dur DURATION, 267 -- aggregated count of the |thread_state| in the txn 268 thread_state_count LONG 269) AS 270SELECT 271 binder_txn_id, 272 client_ts, 273 client_tid, 274 binder_reply_id, 275 server_ts, 276 server_tid, 277 'binder_txn' AS thread_state_type, 278 state AS thread_state, 279 sum(dur) AS thread_state_dur, 280 count(dur) AS thread_state_count 281FROM _sp_binder_txn_thread_state 282GROUP BY 283 binder_txn_id, 284 binder_reply_id, 285 thread_state_type, 286 thread_state 287UNION ALL 288SELECT 289 binder_txn_id, 290 client_ts, 291 client_tid, 292 binder_reply_id, 293 server_ts, 294 server_tid, 295 'binder_reply' AS thread_state_type, 296 state AS thread_state, 297 sum(dur) AS thread_state_dur, 298 count(dur) AS thread_state_count 299FROM _sp_binder_reply_thread_state 300GROUP BY 301 binder_txn_id, 302 binder_reply_id, 303 thread_state_type, 304 thread_state; 305 306-- Aggregated blocked_functions on the client and server side per binder txn 307-- This builds on the data from |_sync_binder_metrics_by_txn| and 308-- for each end (client and server) of the transaction, it returns 309-- the aggregated sum of all the kernel blocked function durations. 310-- The |thread_state_type| column represents whether a given 'aggregated blocked_function' 311-- row is on the client or server side. 'binder_txn' is client side and 'binder_reply' 312-- is server side. 313CREATE PERFETTO VIEW android_sync_binder_blocked_functions_by_txn ( 314 -- slice id of the binder txn 315 binder_txn_id LONG, 316 -- Client ts 317 client_ts TIMESTAMP, 318 -- Client tid 319 client_tid LONG, 320 -- slice id of the binder reply 321 binder_reply_id LONG, 322 -- Server ts 323 server_ts TIMESTAMP, 324 -- Server tid 325 server_tid LONG, 326 -- whether thread state is on the txn or reply side 327 thread_state_type STRING, 328 -- blocked kernel function in a thread state 329 blocked_function STRING, 330 -- aggregated dur of the |blocked_function| in the txn 331 blocked_function_dur DURATION, 332 -- aggregated count of the |blocked_function| in the txn 333 blocked_function_count LONG 334) AS 335SELECT 336 binder_txn_id, 337 client_ts, 338 client_tid, 339 binder_reply_id, 340 server_ts, 341 server_tid, 342 'binder_txn' AS thread_state_type, 343 blocked_function, 344 sum(dur) AS blocked_function_dur, 345 count(dur) AS blocked_function_count 346FROM _sp_binder_txn_thread_state 347WHERE 348 blocked_function IS NOT NULL 349GROUP BY 350 binder_txn_id, 351 binder_reply_id, 352 blocked_function 353UNION ALL 354SELECT 355 binder_txn_id, 356 client_ts, 357 client_tid, 358 binder_reply_id, 359 server_ts, 360 server_tid, 361 'binder_reply' AS thread_state_type, 362 blocked_function, 363 sum(dur) AS blocked_function_dur, 364 count(dur) AS blocked_function_count 365FROM _sp_binder_reply_thread_state 366WHERE 367 blocked_function IS NOT NULL 368GROUP BY 369 binder_txn_id, 370 binder_reply_id, 371 blocked_function; 372 373CREATE PERFETTO TABLE _async_binder_reply AS 374WITH 375 async_reply AS MATERIALIZED ( 376 SELECT 377 id, 378 ts, 379 dur, 380 track_id, 381 name 382 FROM slice 383 WHERE 384 -- Filter for only server side AIDL slices as there are some client side ones for cpp 385 name GLOB 'AIDL::*Server' 386 OR name GLOB 'AIDL::*server' 387 OR name GLOB 'HIDL::*server' 388 OR name = 'binder async rcv' 389 ) 390SELECT 391 *, 392 lead(name) OVER (PARTITION BY track_id ORDER BY ts) AS next_name, 393 lead(ts) OVER (PARTITION BY track_id ORDER BY ts) AS next_ts, 394 lead(dur) OVER (PARTITION BY track_id ORDER BY ts) AS next_dur 395FROM async_reply; 396 397CREATE PERFETTO TABLE _binder_async_txn_raw AS 398SELECT 399 slice.id AS binder_txn_id, 400 process.name AS client_process, 401 thread.name AS client_thread, 402 process.upid AS client_upid, 403 thread.utid AS client_utid, 404 thread.tid AS client_tid, 405 process.pid AS client_pid, 406 thread.is_main_thread, 407 slice.ts AS client_ts, 408 slice.dur AS client_dur 409FROM slice 410JOIN thread_track 411 ON slice.track_id = thread_track.id 412JOIN thread 413 USING (utid) 414JOIN process 415 USING (upid) 416WHERE 417 slice.name = 'binder transaction async'; 418 419CREATE PERFETTO TABLE _binder_async_txn AS 420SELECT 421 iif(binder_reply.next_name = 'binder async rcv', NULL, binder_reply.next_name) AS aidl_name, 422 iif(binder_reply.next_name = 'binder async rcv', NULL, binder_reply.next_ts) AS aidl_ts, 423 iif(binder_reply.next_name = 'binder async rcv', NULL, binder_reply.next_dur) AS aidl_dur, 424 binder_txn.*, 425 binder_reply.id AS binder_reply_id, 426 reply_process.name AS server_process, 427 reply_thread.name AS server_thread, 428 reply_process.upid AS server_upid, 429 reply_thread.utid AS server_utid, 430 reply_thread.tid AS server_tid, 431 reply_process.pid AS server_pid, 432 binder_reply.ts AS server_ts, 433 binder_reply.dur AS server_dur 434FROM _binder_async_txn_raw AS binder_txn 435JOIN flow AS binder_flow 436 ON binder_txn.binder_txn_id = binder_flow.slice_out 437JOIN _async_binder_reply AS binder_reply 438 ON binder_flow.slice_in = binder_reply.id 439JOIN thread_track AS reply_thread_track 440 ON binder_reply.track_id = reply_thread_track.id 441JOIN thread AS reply_thread 442 ON reply_thread.utid = reply_thread_track.utid 443JOIN process AS reply_process 444 ON reply_process.upid = reply_thread.upid 445WHERE 446 binder_reply.name = 'binder async rcv'; 447 448-- Breakdown asynchronous binder transactions per txn. 449-- It returns data about the client and server ends of every binder transaction async. 450CREATE PERFETTO VIEW _async_binder_metrics_by_txn AS 451SELECT 452 binder.*, 453 client_oom.value AS client_oom_score, 454 server_oom.value AS server_oom_score 455FROM _binder_async_txn AS binder 456LEFT JOIN _oom_score AS client_oom 457 ON binder.client_upid = client_oom.upid 458 AND binder.client_ts BETWEEN client_oom.ts AND client_oom.end_ts 459LEFT JOIN _oom_score AS server_oom 460 ON binder.server_upid = server_oom.upid 461 AND binder.server_ts BETWEEN server_oom.ts AND server_oom.end_ts; 462 463-- Breakdown binder transactions per txn. 464-- It returns data about the client and server ends of every binder transaction async. 465CREATE PERFETTO TABLE android_binder_txns ( 466 -- Fully qualified name of the binder endpoint if existing. 467 aidl_name STRING, 468 -- Interface of the binder endpoint if existing. 469 interface STRING, 470 -- Method name of the binder endpoint if existing. 471 method_name STRING, 472 -- Timestamp the binder interface name was emitted. Proxy to 'ts' and 'dur' for async txns. 473 aidl_ts TIMESTAMP, 474 -- Duration of the binder interface name. Proxy to 'ts' and 'dur' for async txns. 475 aidl_dur DURATION, 476 -- Slice id of the binder txn. 477 binder_txn_id JOINID(slice.id), 478 -- Name of the client process. 479 client_process STRING, 480 -- Name of the client thread. 481 client_thread STRING, 482 -- Upid of the client process. 483 client_upid JOINID(process.id), 484 -- Utid of the client thread. 485 client_utid JOINID(thread.id), 486 -- Tid of the client thread. 487 client_tid LONG, 488 -- Pid of the client thread. 489 client_pid LONG, 490 -- Whether the txn was initiated from the main thread of the client process. 491 is_main_thread BOOL, 492 -- Timestamp of the client txn. 493 client_ts TIMESTAMP, 494 -- Wall clock dur of the client txn. 495 client_dur DURATION, 496 -- Slice id of the binder reply. 497 binder_reply_id JOINID(slice.id), 498 -- Name of the server process. 499 server_process STRING, 500 -- Name of the server thread. 501 server_thread STRING, 502 -- Upid of the server process. 503 server_upid JOINID(process.id), 504 -- Utid of the server thread. 505 server_utid JOINID(thread.id), 506 -- Tid of the server thread. 507 server_tid LONG, 508 -- Pid of the server thread. 509 server_pid LONG, 510 -- Timestamp of the server txn. 511 server_ts TIMESTAMP, 512 -- Wall clock dur of the server txn. 513 server_dur DURATION, 514 -- Oom score of the client process at the start of the txn. 515 client_oom_score LONG, 516 -- Oom score of the server process at the start of the reply. 517 server_oom_score LONG, 518 -- Whether the txn is synchronous or async (oneway). 519 is_sync BOOL, 520 -- Monotonic clock dur of the client txn. 521 client_monotonic_dur DURATION, 522 -- Monotonic clock dur of the server txn. 523 server_monotonic_dur DURATION, 524 -- Client package version_code. 525 client_package_version_code LONG, 526 -- Server package version_code. 527 server_package_version_code LONG, 528 -- Whether client package is debuggable. 529 is_client_package_debuggable BOOL, 530 -- Whether server package is debuggable. 531 is_server_package_debuggable BOOL 532) AS 533WITH 534 all_binder AS ( 535 SELECT 536 *, 537 1 AS is_sync 538 FROM _sync_binder_metrics_by_txn 539 UNION ALL 540 SELECT 541 *, 542 0 AS is_sync 543 FROM _async_binder_metrics_by_txn 544 ) 545SELECT 546 str_split(aidl_name, '::', 2) AS interface, 547 str_split(aidl_name, '::', 3) AS method_name, 548 all_binder.*, 549 _extract_duration_without_suspend(client_ts, client_dur) AS client_monotonic_dur, 550 _extract_duration_without_suspend(server_ts, server_dur) AS server_monotonic_dur, 551 client_process_metadata.version_code AS client_package_version_code, 552 server_process_metadata.version_code AS server_package_version_code, 553 client_process_metadata.debuggable AS is_client_package_debuggable, 554 server_process_metadata.debuggable AS is_server_package_debuggable 555FROM all_binder 556LEFT JOIN android_process_metadata AS client_process_metadata 557 ON all_binder.client_upid = client_process_metadata.upid 558LEFT JOIN android_process_metadata AS server_process_metadata 559 ON all_binder.server_upid = server_process_metadata.upid; 560 561-- Returns a DAG of all outgoing binder txns from a process. 562-- The roots of the graph are the threads making the txns and the graph flows from: 563-- thread -> server_process -> AIDL interface -> AIDL method. 564-- The weights of each node represent the wall execution time in the server_process. 565CREATE PERFETTO FUNCTION android_binder_outgoing_graph( 566 -- Upid of process to generate an outgoing graph for. 567 upid JOINID(process.id) 568) 569RETURNS TABLE ( 570 -- Pprof of outgoing binder txns. 571 pprof BYTES 572) AS 573WITH 574 threads AS ( 575 SELECT 576 binder_txn_id, 577 cat_stacks(client_thread) AS stack 578 FROM android_binder_txns 579 WHERE 580 ( 581 NOT $upid IS NULL AND client_upid = $upid 582 ) OR ( 583 $upid IS NULL 584 ) 585 ), 586 server_process AS ( 587 SELECT 588 binder_txn_id, 589 cat_stacks(stack, server_process) AS stack 590 FROM android_binder_txns 591 JOIN threads 592 USING (binder_txn_id) 593 ), 594 end_points AS ( 595 SELECT 596 binder_txn_id, 597 cat_stacks(stack, str_split(aidl_name, '::', iif(aidl_name GLOB 'AIDL*', 2, 1))) AS stack 598 FROM android_binder_txns 599 JOIN server_process 600 USING (binder_txn_id) 601 ), 602 aidl_names AS ( 603 SELECT 604 binder_txn_id, 605 server_dur, 606 cat_stacks(stack, str_split(aidl_name, '::', iif(aidl_name GLOB 'AIDL*', 3, 2))) AS stack 607 FROM android_binder_txns 608 JOIN end_points 609 USING (binder_txn_id) 610 ) 611SELECT 612 experimental_profile(stack, 'duration', 'ns', server_dur) AS pprof 613FROM aidl_names; 614 615-- Returns a DAG of all incoming binder txns from a process. 616-- The roots of the graph are the clients making the txns and the graph flows from: 617-- client_process -> AIDL interface -> AIDL method. 618-- The weights of each node represent the wall execution time in the server_process. 619CREATE PERFETTO FUNCTION android_binder_incoming_graph( 620 -- Upid of process to generate an incoming graph for. 621 upid JOINID(process.id) 622) 623RETURNS TABLE ( 624 -- Pprof of incoming binder txns. 625 pprof BYTES 626) AS 627WITH 628 client_process AS ( 629 SELECT 630 binder_txn_id, 631 cat_stacks(client_process) AS stack 632 FROM android_binder_txns 633 WHERE 634 ( 635 NOT $upid IS NULL AND server_upid = $upid 636 ) OR ( 637 $upid IS NULL 638 ) 639 ), 640 end_points AS ( 641 SELECT 642 binder_txn_id, 643 cat_stacks(stack, str_split(aidl_name, '::', iif(aidl_name GLOB 'AIDL*', 2, 1))) AS stack 644 FROM android_binder_txns 645 JOIN client_process 646 USING (binder_txn_id) 647 ), 648 aidl_names AS ( 649 SELECT 650 binder_txn_id, 651 server_dur, 652 cat_stacks(stack, str_split(aidl_name, '::', iif(aidl_name GLOB 'AIDL*', 3, 2))) AS stack 653 FROM android_binder_txns 654 JOIN end_points 655 USING (binder_txn_id) 656 ) 657SELECT 658 experimental_profile(stack, 'duration', 'ns', server_dur) AS pprof 659FROM aidl_names; 660 661-- Returns a graph of all binder txns in a trace. 662-- The nodes are client_process and server_process. 663-- The weights of each node represent the wall execution time in the server_process. 664CREATE PERFETTO FUNCTION android_binder_graph( 665 -- Matches txns from client_processes greater than or equal to the OOM score. 666 min_client_oom_score LONG, 667 -- Matches txns from client_processes less than or equal to the OOM score. 668 max_client_oom_score LONG, 669 -- Matches txns to server_processes greater than or equal to the OOM score. 670 min_server_oom_score LONG, 671 -- Matches txns to server_processes less than or equal to the OOM score. 672 max_server_oom_score LONG 673) 674RETURNS TABLE ( 675 -- Pprof of binder txns. 676 pprof BYTES 677) AS 678WITH 679 clients AS ( 680 SELECT 681 binder_txn_id, 682 cat_stacks(client_process) AS stack 683 FROM android_binder_txns 684 WHERE 685 client_oom_score BETWEEN $min_client_oom_score AND $max_client_oom_score 686 ), 687 servers AS ( 688 SELECT 689 binder_txn_id, 690 server_dur, 691 cat_stacks(stack, server_process) AS stack 692 FROM android_binder_txns 693 JOIN clients 694 USING (binder_txn_id) 695 WHERE 696 server_oom_score BETWEEN $min_server_oom_score AND $max_server_oom_score 697 ) 698SELECT 699 experimental_profile(stack, 'duration', 'ns', server_dur) AS pprof 700FROM servers; 701