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-- WARNING: This metric should not be used as a source of truth. It is under 17-- active development and the values & meaning might change without 18-- notice. 19 20INCLUDE PERFETTO MODULE chrome.tasks; 21 22-- Extract mojo information for the long-task-tracking scenario for specific 23-- names. For example, LongTaskTracker slices may have associated IPC 24-- metadata, or InterestingTask slices for input may have associated IPC to 25-- determine whether the task is fling/etc. 26CREATE OR REPLACE PERFETTO FUNCTION select_long_task_slices(name STRING) 27RETURNS TABLE( 28 interface_name STRING, 29 ipc_hash INT, 30 message_type STRING, 31 id INT, 32 task_name STRING) 33AS 34WITH slices_with_mojo_data AS ( 35 SELECT 36 EXTRACT_ARG( 37 arg_set_id, 38 "chrome_mojo_event_info.mojo_interface_tag" 39 ) AS interface_name, 40 EXTRACT_ARG( 41 arg_set_id, 42 "chrome_mojo_event_info.ipc_hash" 43 ) AS ipc_hash, 44 CASE 45 WHEN EXTRACT_ARG(arg_set_id, "chrome_mojo_event_info.is_reply") THEN "reply" 46 ELSE "message" 47 END AS message_type, 48 id 49 FROM slice 50 WHERE 51 category GLOB "*scheduler.long_tasks*" 52 AND name = $name 53) 54SELECT 55 *, 56 printf("%s %s(hash=%s)", interface_name, message_type, ipc_hash) as task_name 57FROM slices_with_mojo_data; 58 59CREATE OR REPLACE PERFETTO FUNCTION is_long_choreographer_task(dur LONG) 60RETURNS BOOL AS 61SELECT $dur >= 4 * 1e6; 62 63-- Note that not all slices will be mojo slices; filter on interface_name IS 64-- NOT NULL for mojo slices specifically. 65DROP TABLE IF EXISTS long_tasks_extracted_slices; 66CREATE PERFETTO TABLE long_tasks_extracted_slices AS 67SELECT * FROM SELECT_LONG_TASK_SLICES(/*name*/'LongTaskTracker'); 68 69-- Create |long_tasks_internal_tbl| table, which gathers all of the 70-- information needed to produce the full name + metadata required 71-- for LongTaskTracker slices. Unlike toplevel slices, which will 72-- have nested descendants, LongTaskTracker slices will store all of 73-- the relevant information within the single slice. 74DROP TABLE IF EXISTS long_tasks_internal_tbl; 75CREATE PERFETTO TABLE long_tasks_internal_tbl AS 76WITH 77 raw_extracted_values AS ( 78 SELECT 79 mojo.id, 80 mojo.interface_name, 81 mojo.ipc_hash, 82 mojo.message_type, 83 _get_posted_from(s.arg_set_id) as posted_from 84 FROM long_tasks_extracted_slices mojo 85 JOIN slice s ON mojo.id = s.id 86 ) 87SELECT 88 id, 89 CASE 90 WHEN interface_name IS NOT NULL 91 THEN printf('%s %s (hash=%d)', interface_name, message_type, ipc_hash) 92 ELSE 93 _format_scheduler_task_name(posted_from) 94 END AS full_name, 95 interface_name IS NOT NULL AS is_mojo 96FROM raw_extracted_values; 97 98-- Attach java views to its associated LongTaskTracker slice, as they 99-- will be on different tracks. This follows the same logic as creating 100-- chrome_slices_with_java_views_internal, differing only in how a 101-- descendent is calculated. 102DROP VIEW IF EXISTS long_task_slices_with_java_views; 103CREATE PERFETTO VIEW long_task_slices_with_java_views AS 104WITH 105 -- Select UI thread BeginMainFrames frames. 106 root_slices AS ( 107 SELECT * 108 FROM _SELECT_BEGIN_MAIN_FRAME_JAVA_SLICES('LongTaskTracker') 109 UNION ALL 110 SELECT id, "Choreographer" as kind, ts, dur, name 111 FROM slice 112 WHERE is_long_choreographer_task(dur) 113 AND name GLOB "Looper.dispatch: android.view.Choreographer$FrameHandler*" 114 ), 115 -- Intermediate step to allow us to sort java view names. 116 root_slice_and_java_view_not_grouped AS ( 117 SELECT 118 s1.id, s1.kind, s2.name AS java_view_name 119 FROM root_slices s1 120 JOIN _chrome_java_views s2 121 ON ( 122 s1.ts < s2.ts AND s1.ts + s1.dur > s2.ts + s2.dur) 123 ) 124SELECT 125 s1.id, 126 s1.kind, 127 GROUP_CONCAT(DISTINCT s2.java_view_name) AS java_views 128FROM root_slices s1 129LEFT JOIN root_slice_and_java_view_not_grouped s2 130 USING (id) 131GROUP BY s1.id; 132 133DROP VIEW IF EXISTS chrome_long_tasks_internal; 134CREATE PERFETTO VIEW chrome_long_tasks_internal AS 135WITH -- Generate full names for tasks with java views. 136 java_views_tasks AS ( 137 SELECT 138 printf('%s(java_views=%s)', kind, java_views) as full_name, 139 _get_java_views_task_type(kind) AS task_type, 140 id 141 FROM long_task_slices_with_java_views 142 WHERE kind = "SingleThreadProxy::BeginMainFrame" 143 ), 144 scheduler_tasks_with_mojo AS ( 145 SELECT 146 full_name, 147 'mojo' as task_type, 148 id 149 FROM long_tasks_internal_tbl 150 WHERE is_mojo 151 ), 152 navigation_tasks AS ( 153 SELECT 154 -- NOTE: unless Navigation category is enabled and recorded on the same 155 -- track as the LongTaskTracker slice, frame type will always be unknown. 156 printf('%s (%s)', 157 _human_readable_navigation_task_name(full_name), 158 IFNULL(_extract_frame_type(id), 'unknown frame type')) AS full_name, 159 'navigation_task' AS task_type, 160 id 161 FROM scheduler_tasks_with_mojo 162 WHERE _human_readable_navigation_task_name(full_name) IS NOT NULL 163 ) 164SELECT 165 COALESCE(s4.full_name, s3.full_name, s2.full_name, s1.full_name) AS full_name, 166 COALESCE(s4.task_type, s3.task_type, s2.task_type, 'scheduler') as task_type, 167 s1.id as id 168FROM long_tasks_internal_tbl s1 169LEFT JOIN scheduler_tasks_with_mojo s2 ON s2.id = s1.id 170LEFT JOIN java_views_tasks s3 ON s3.id = s1.id 171LEFT JOIN navigation_tasks s4 ON s4.id = s1.id 172UNION ALL 173-- Choreographer slices won't necessarily be associated with an overlying 174-- LongTaskTracker slice, so join them separately. 175SELECT 176 printf('%s(java_views=%s)', kind, java_views) as full_name, 177 _get_java_views_task_type(kind) AS task_type, 178 id 179FROM long_task_slices_with_java_views 180WHERE kind = "Choreographer"; 181 182DROP VIEW IF EXISTS chrome_long_tasks; 183CREATE PERFETTO VIEW chrome_long_tasks AS 184SELECT 185 full_name, 186 task_type, 187 thread.name AS thread_name, 188 thread.utid, 189 process.name AS process_name, 190 thread.upid, 191 ts.* 192FROM chrome_long_tasks_internal cti 193JOIN slice ts USING (id) 194JOIN thread_track tt ON ts.track_id = tt.id 195JOIN thread USING (utid) 196JOIN process USING (upid); 197