• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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