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 17SELECT IMPORT("common.slices"); 18 19SELECT CREATE_FUNCTION( 20 '{{function_prefix}}EXTRACT_MOJO_IPC_HASH(slice_id INT)', 21 'INT', 22 ' 23 SELECT EXTRACT_ARG(s2.arg_set_id, "chrome_mojo_event_info.ipc_hash") 24 FROM descendant_slice($slice_id) s2 25 WHERE s2.name="ScopedSetIpcHash" 26 ORDER BY s2.id 27 LIMIT 1 28 ' 29); 30 31SELECT CREATE_FUNCTION( 32 '{{function_prefix}}EXTRACT_FRAME_TYPE(slice_id INT)', 33 'INT', 34 ' 35 SELECT EXTRACT_ARG(descendants.arg_set_id, "render_frame_host.frame_type") 36 FROM descendant_slice($slice_id) descendants 37 WHERE descendants.name IN ("RenderFrameHostImpl::BeginNavigation", 38 "RenderFrameHostImpl::DidCommitProvisionalLoad", 39 "RenderFrameHostImpl::DidCommitSameDocumentNavigation", 40 "RenderFrameHostImpl::DidStopLoading") 41 LIMIT 1 42 ' 43); 44 45-- Selects the ScheduledActionSendBeginMainFrame slices, used for root-level 46-- processing. In top-level/Java based slices, these will correspond with the 47-- ancestor of descendant slices; in long-task tracking, these tasks will be 48-- on a custom track and will need to be associated with children by timestamp 49-- and duration. Corresponds with the Choreographer root slices in 50-- chrome_choreographer_tasks below. 51-- 52-- Schema: 53-- @column is The slice id. 54-- @column kind The type of Java slice. 55-- @column ts The timestamp of the slice. 56-- @column name The name of the slice. 57-- 58-- Power states are encoded as non-negative integers, with zero representing 59-- full-power operation and positive values representing increasingly deep 60-- sleep states. 61SELECT CREATE_VIEW_FUNCTION( 62 'SELECT_BEGIN_MAIN_FRAME_JAVA_SLICES(name STRING)', 63 'id INT, kind STRING, ts LONG, dur LONG, name STRING', 64 'SELECT 65 id, 66 "SingleThreadProxy::BeginMainFrame" AS kind, 67 ts, 68 dur, 69 name 70 FROM slice 71 WHERE 72 (name = $name 73 AND EXTRACT_ARG(arg_set_id, "task.posted_from.file_name") = "cc/trees/single_thread_proxy.cc" 74 AND EXTRACT_ARG(arg_set_id, "task.posted_from.function_name") = "ScheduledActionSendBeginMainFrame") 75 ' 76); 77 78SELECT CREATE_FUNCTION( 79 -- Function prototype: takes a formatted chrome scheduler task name and 80 -- returns a readable task name. 81 '{{function_prefix}}HUMAN_READABLE_NAVIGATION_TASK_NAME(full_name STRING)', 82 'STRING', 83 'SELECT 84 CASE 85 WHEN $full_name = "content.mojom.FrameHost message (hash=2168461044)" THEN "FrameHost::BeginNavigation" 86 WHEN $full_name = "content.mojom.FrameHost message (hash=3561497419)" THEN "FrameHost::DidCommitProvisionalLoad" 87 WHEN $full_name = "content.mojom.FrameHost message (hash=1421450774)" THEN "FrameHost::DidCommitSameDocumentNavigation" 88 WHEN $full_name = "content.mojom.FrameHost message (hash=368650583)" THEN "FrameHost::DidStopLoading" 89 END 90 ' 91); 92 93SELECT CREATE_FUNCTION( 94 -- Function prototype: takes a task name and formats it correctly for 95 -- scheduler tasks. 96 '{{function_prefix}}FORMAT_SCHEDULER_TASK_NAME(full_name STRING)', 97 'STRING', 98 'SELECT 99 printf("RunTask(posted_from=%s)", $full_name) 100 ' 101); 102 103SELECT CREATE_FUNCTION( 104 -- Function prototype: takes the category and determines whether it is "Java" 105 -- only, as opposed to "toplevel,Java". 106 '{{function_prefix}}JAVA_NOT_TOP_LEVEL_CATEGORY(category STRING)', 107 'BOOL', 108 'SELECT 109 $category GLOB "*Java*" AND $category not GLOB "*toplevel*" 110 ' 111); 112 113SELECT CREATE_FUNCTION( 114 -- Function prototype: takes the category and determines whether is any valid 115 -- toplevel category or combination of categories. 116 '{{function_prefix}}ANY_TOP_LEVEL_CATEGORY(category STRING)', 117 'BOOL', 118 'SELECT 119 $category IN ("toplevel", "toplevel,viz", "toplevel,Java") 120 ' 121); 122 123SELECT CREATE_FUNCTION( 124 -- Function prototype: takes a task name and formats it correctly for 125 -- scheduler tasks. 126 '{{function_prefix}}GET_JAVA_VIEWS_TASK_TYPE(kind STRING)', 127 'STRING', 128 'SELECT 129 (CASE $kind 130 WHEN "Choreographer" THEN "choreographer" 131 WHEN "SingleThreadProxy::BeginMainFrame" THEN "ui_thread_begin_main_frame" 132 END) 133 ' 134); 135 136-- Create |chrome_mojo_slices_tbl| table, containing a subset of slice 137-- table with the slices corresponding to mojo messages. 138-- 139-- Note: this might include messages received within a sync mojo call. 140DROP TABLE IF EXISTS chrome_mojo_slices_tbl; 141CREATE TABLE chrome_mojo_slices_tbl AS 142WITH 143-- Select all new-style (post crrev.com/c/3270337) mojo slices and 144-- generate |full_name| for them. 145-- If extended tracing is enabled, the slice name will have the full method 146-- name (i.e. "Receive content::mojom::FrameHost::DidStopLoading") and we 147-- should use it as a full name. 148-- If extended tracing is not enabled, we should include the interface name 149-- and method hash into the full name. 150new_mojo_slices AS ( 151 SELECT 152 EXTRACT_ARG(s.arg_set_id, "chrome_mojo_event_info.mojo_interface_tag") AS interface_name, 153 EXTRACT_ARG(arg_set_id, "chrome_mojo_event_info.ipc_hash") AS ipc_hash, 154 CASE name 155 WHEN "Receive mojo message" THEN "message" 156 WHEN "Receive mojo reply" THEN "reply" 157 END AS message_type, 158 s.id 159 FROM {{slice_table_name}} s 160 WHERE 161 category GLOB "*toplevel*" 162 AND name GLOB 'Receive *' 163), 164-- Select old-style slices for channel-associated mojo events. 165old_associated_mojo_slices AS ( 166 SELECT 167 s.name AS interface_name, 168 {{function_prefix}}EXTRACT_MOJO_IPC_HASH(s.id) AS ipc_hash, 169 "message" AS message_type, 170 s.id 171 FROM {{slice_table_name}} s 172 WHERE 173 category GLOB "*mojom*" 174 AND name GLOB '*.mojom.*' 175), 176-- Select old-style slices for non-(channel-associated) mojo events. 177old_non_associated_mojo_slices AS ( 178 SELECT 179 COALESCE( 180 EXTRACT_ARG(s.arg_set_id, "chrome_mojo_event_info.watcher_notify_interface_tag"), 181 EXTRACT_ARG(s.arg_set_id, "chrome_mojo_event_info.mojo_interface_tag") 182 ) AS interface_name, 183 {{function_prefix}}EXTRACT_MOJO_IPC_HASH(s.id) AS ipc_hash, 184 "message" AS message_type, 185 s.id 186 FROM {{slice_table_name}} s 187 WHERE 188 category GLOB "*toplevel*" AND name = "Connector::DispatchMessage" 189) 190-- Merge all mojo slices. 191SELECT * FROM new_mojo_slices 192UNION ALL 193SELECT * FROM old_associated_mojo_slices 194UNION ALL 195SELECT * FROM old_non_associated_mojo_slices; 196 197-- As we lookup by ID on |chrome_mojo_slices_tbl| table, add an index on 198-- id to make lookups fast. 199DROP INDEX IF EXISTS chrome_mojo_slices_idx; 200CREATE INDEX chrome_mojo_slices_idx ON chrome_mojo_slices_tbl(id); 201 202-- This table contains a list of slices corresponding to the _representative_ Chrome Java views. 203-- These are the outermost Java view slices after filtering out generic framework views 204-- (like FitWindowsLinearLayout) and selecting the outermost slices from the remaining ones. 205DROP TABLE IF EXISTS chrome_java_views_internal; 206CREATE TABLE chrome_java_views_internal AS 207WITH 208-- .draw, .onLayout and .onMeasure parts of the java view names don't add much, strip them. 209java_slices_with_trimmed_names AS ( 210 SELECT 211 id, 212 REPLACE( 213 REPLACE( 214 REPLACE( 215 REPLACE( 216 REPLACE( 217 s1.name, 218 ".draw", ""), 219 ".onLayout", ""), 220 ".onMeasure", ""), 221 ".Layout", ""), 222 ".Measure", "") AS name, 223 ts, 224 dur 225 FROM 226 {{slice_table_name}} s1 227 -- Ensure that toplevel Java slices are not included, as they may be logged 228 -- with either category = "toplevel" or category = "toplevel,Java". 229 WHERE {{function_prefix}}JAVA_NOT_TOP_LEVEL_CATEGORY(category) AND dur > 0 230 ), 231 -- We filter out generic slices from various UI frameworks which don't tell us much about 232 -- what exactly this view is doing. 233 interesting_java_slices AS ( 234 SELECT 235 id, name, ts, dur 236 FROM java_slices_with_trimmed_names 237 WHERE NOT name IN ( 238 -- AndroidX. 239 "FitWindowsFrameLayout", 240 "FitWindowsLinearLayout", 241 "ContentFrameLayout", 242 "CoordinatorLayout", 243 -- Other non-Chrome UI libraries. 244 "ComponentHost", 245 -- Generic Chrome frameworks. 246 "CompositorView:finalizeLayers", 247 "CompositorViewHolder", 248 "CompositorViewHolder:layout", 249 "CompositorViewHolder:updateContentViewChildrenDimension", 250 "CoordinatorLayoutForPointer", 251 "OptimizedFrameLayout", 252 "ViewResourceAdapter:getBitmap", 253 "ViewResourceFrameLayout", 254 -- Non-specific Chrome slices. 255 "AppCompatImageButton", 256 "ScrollingBottomViewResourceFrameLayout", 257 -- Screenshots get their custom annotations below. 258 "ViewResourceAdapter:captureWithHardwareDraw", 259 "ViewResourceAdapter:captureWithSoftwareDraw", 260 -- Non-bytecode generated slices. 261 "LayoutDriver:onUpdate" 262 ) 263) 264SELECT 265 s1.*, 266 -- While the parent slices are too generic to be used by themselves, 267 -- they can provide some useful metadata. 268 HAS_PARENT_SLICE_WITH_NAME( 269 s1.id, 270 "ViewResourceAdapter:captureWithSoftwareDraw" 271 ) AS is_software_screenshot, 272 HAS_PARENT_SLICE_WITH_NAME( 273 s1.id, 274 "ViewResourceAdapter:captureWithHardwareDraw" 275 ) AS is_hardware_screenshot 276FROM interesting_java_slices s1 277WHERE (SELECT count() 278 FROM ancestor_slice(s1.id) s2 279 JOIN interesting_java_slices s3 ON s2.id = s3.id) = 0; 280 281-- |chrome_java_views| is a view over |chrome_java_views_internal| table, adding the necessary columns 282-- from |slice|. 283DROP VIEW IF EXISTS chrome_java_views; 284CREATE VIEW chrome_java_views AS 285SELECT 286 s1.name AS filtered_name, 287 s1.is_software_screenshot, 288 s1.is_hardware_screenshot, 289 s2.* 290FROM chrome_java_views_internal s1 291JOIN {{slice_table_name}} s2 USING (id); 292 293DROP VIEW IF EXISTS chrome_choreographer_tasks; 294CREATE VIEW chrome_choreographer_tasks 295AS 296SELECT 297 id, 298 "Choreographer" AS kind, 299 ts, 300 dur, 301 name 302FROM slice 303WHERE 304 name GLOB "Looper.dispatch: android.view.Choreographer$FrameHandler*"; 305 306-- Most of java views will be triggered either by Chrome's BeginMainFrame 307-- or by Android's Choreographer. 308DROP VIEW IF EXISTS chrome_slices_with_java_views_internal; 309CREATE VIEW chrome_slices_with_java_views_internal AS 310WITH 311 -- Select UI thread BeginMainFrames and Choreographer frames. 312 root_slices AS ( 313 SELECT * 314 FROM SELECT_BEGIN_MAIN_FRAME_JAVA_SLICES('ThreadControllerImpl::RunTask') 315 UNION ALL 316 SELECT * FROM chrome_choreographer_tasks 317 ), 318 -- Intermediate step to allow us to sort java view names. 319 root_slice_and_java_view_not_grouped AS ( 320 SELECT 321 s1.id, s1.kind, s3.name AS java_view_name 322 FROM root_slices s1 323 JOIN descendant_slice(s1.id) s2 324 JOIN chrome_java_views_internal s3 ON s2.id = s3.id 325 ) 326SELECT 327 s1.id, 328 s1.kind, 329 GROUP_CONCAT(DISTINCT s2.java_view_name) AS java_views 330FROM root_slices s1 331LEFT JOIN root_slice_and_java_view_not_grouped s2 USING (id) 332GROUP BY s1.id; 333 334-- Create |chrome_tasks| table, which contains a subset of slice 335-- table of the slices which should be considered top-level Chrome tasks with the 336-- additional scheduler_type |full_name| column, derived from subevents. 337DROP TABLE IF EXISTS chrome_tasks_internal; 338CREATE TABLE chrome_tasks_internal AS 339WITH 340-- Select slices from "toplevel" category which do not have another 341-- "toplevel" slice as ancestor. The possible cases include sync mojo messages 342-- and tasks in nested runloops. Toplevel events may also be logged as with 343-- the Java category. 344non_embedded_toplevel_slices AS ( 345 SELECT * FROM {{slice_table_name}} s 346 WHERE 347 {{function_prefix}}ANY_TOP_LEVEL_CATEGORY(category) 348 AND (SELECT count() FROM ancestor_slice(s.id) s2 349 WHERE s2.category GLOB "*toplevel*" or s2.category GLOB "*toplevel.viz*") = 0 350), 351-- Select slices from "Java" category which do not have another "Java" or 352-- "toplevel" slice as parent. In the longer term they should probably belong 353-- to "toplevel" category as well, but for now this will have to do. Ensure 354-- that "Java" slices do not include "toplevel" slices as those would be 355-- handled elsewhere. 356non_embedded_java_slices AS ( 357 SELECT name AS full_name, "java" AS task_type, id 358 FROM {{slice_table_name}} s 359 WHERE 360 {{function_prefix}}JAVA_NOT_TOP_LEVEL_CATEGORY(category) 361 AND (SELECT count() 362 FROM ancestor_slice(s.id) s2 363 WHERE s2.category GLOB "*toplevel*" OR s2.category GLOB "*Java*") = 0 364), 365raw_scheduler_tasks AS ( 366 SELECT 367 EXTRACT_ARG(s.arg_set_id, "task.posted_from.file_name") AS posted_from_file_name, 368 EXTRACT_ARG(s.arg_set_id, "task.posted_from.function_name") AS posted_from_function_name, 369 (CASE name 370 WHEN "ThreadControllerImpl::RunTask" THEN "SequenceManager" 371 WHEN "ThreadPool_RunTask" THEN "ThreadPool" 372 END) AS scheduler_type, 373 s.id 374 FROM {{slice_table_name}} s 375 WHERE 376 category GLOB "*toplevel*" 377 AND (name = "ThreadControllerImpl::RunTask" OR name = "ThreadPool_RunTask") 378), 379scheduler_tasks AS ( 380 SELECT 381 s1.posted_from_file_name || ":" || s1.posted_from_function_name AS posted_from, 382 s1.posted_from_file_name, 383 s1.posted_from_function_name, 384 s1.scheduler_type, 385 s1.id 386 FROM raw_scheduler_tasks s1 387), 388-- Generate full names for scheduler tasks. 389scheduler_tasks_with_full_names AS ( 390 SELECT 391 {{function_prefix}}FORMAT_SCHEDULER_TASK_NAME(s.posted_from) AS full_name, 392 "scheduler" AS task_type, 393 s.id 394 FROM scheduler_tasks s 395), 396-- Generate full names for mojo slices. 397mojo_slices AS ( 398 SELECT 399 printf('%s %s (hash=%d)', 400 interface_name, message_type, ipc_hash) AS full_name, 401 "mojo" AS task_type, 402 id 403 FROM chrome_mojo_slices_tbl 404), 405-- Generate full names for tasks with java views. 406java_views_tasks AS ( 407 SELECT 408 printf('%s(java_views=%s)', kind, java_views) AS full_name, 409 {{function_prefix}}GET_JAVA_VIEWS_TASK_TYPE(kind) AS task_type, 410 id 411 FROM chrome_slices_with_java_views_internal 412), 413-- Select scheduler tasks which are used to run mojo messages and use the mojo names 414-- as full names for these slices. 415-- We restrict this to specific scheduler tasks which are expected to run mojo 416-- tasks due to sync mojo events, which also emit similar events. 417scheduler_tasks_with_mojo AS ( 418 SELECT 419 (SELECT s3.full_name 420 FROM descendant_slice(s1.id) s2 421 JOIN mojo_slices s3 USING (id) 422 ORDER BY s2.depth LIMIT 1) AS full_name, 423 "mojo" AS task_type, 424 s1.id 425 FROM 426 scheduler_tasks s1 427 WHERE 428 s1.posted_from IN ( 429 "mojo/public/cpp/system/simple_watcher.cc:Notify", 430 "mojo/public/cpp/system/simple_watcher.cc:ArmOrNotify", 431 "mojo/public/cpp/bindings/lib/connector.cc:PostDispatchNextMessageFromPipe", 432 "ipc/ipc_mojo_bootstrap.cc:Accept") 433), 434navigation_tasks AS ( 435 SELECT 436 printf("%s (%s)", 437 {{function_prefix}}HUMAN_READABLE_NAVIGATION_TASK_NAME(full_name), 438 IFNULL({{function_prefix}}EXTRACT_FRAME_TYPE(id), 'unknown frame type')) AS full_name, 439 'navigation_task' AS task_type, 440 id 441 FROM ( 442 SELECT * FROM scheduler_tasks_with_mojo 443 WHERE {{function_prefix}}HUMAN_READABLE_NAVIGATION_TASK_NAME(full_name) IS NOT NULL 444 ) 445), 446-- Add scheduler and mojo full names to non-embedded slices from 447-- the "toplevel" category, with mojo ones taking precedence. 448non_embedded_toplevel_slices_with_full_name AS ( 449 SELECT 450 COALESCE(s5.full_name, s4.full_name, s2.full_name, s3.full_name, s1.name) AS full_name, 451 COALESCE(s5.task_type, s4.task_type, s2.task_type, s3.task_type, "other") AS task_type, 452 s1.id AS id 453 FROM non_embedded_toplevel_slices s1 454 LEFT JOIN scheduler_tasks_with_mojo s2 ON s2.id = s1.id 455 LEFT JOIN scheduler_tasks_with_full_names s3 ON s3.id = s1.id 456 LEFT JOIN java_views_tasks s4 ON s4.id = s1.id 457 LEFT JOIN navigation_tasks s5 ON s5.id = s1.id 458) 459-- Merge slices from toplevel and Java categories. 460SELECT * FROM non_embedded_toplevel_slices_with_full_name 461UNION ALL 462SELECT * FROM non_embedded_java_slices; 463 464DROP VIEW IF EXISTS chrome_tasks; 465CREATE VIEW chrome_tasks AS 466SELECT 467 full_name, 468 task_type, 469 thread.name AS thread_name, 470 thread.utid, 471 process.name AS process_name, 472 thread.upid, 473 ts.* 474FROM chrome_tasks_internal cti 475JOIN {{slice_table_name}} ts USING (id) 476JOIN thread_track tt ON ts.track_id = tt.id 477JOIN thread USING (utid) 478JOIN process USING (upid); 479 480-- A helper view into Chrome thread slices which don't have a parent task. 481-- TODO(altimin): Use chrome_thread here once it's reliable. 482DROP VIEW IF EXISTS chrome_slices_without_parent_task; 483CREATE VIEW chrome_slices_without_parent_task AS 484SELECT 485 s1.* 486FROM {{slice_table_name}} s1 487LEFT JOIN chrome_tasks s2 USING (id) 488WHERE 489 (SELECT count() 490 FROM ancestor_slice(s1.id) s3 491 JOIN chrome_tasks s4 ON s3.id = s4.id) = 0 492 AND s2.id IS NULL; 493