• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1--
2-- Copyright 2024 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 graphs.search;
18
19-- Computes critical paths, the dependency graph of a task.
20-- The critical path is a set of edges reachable from a root node with the sum of the edge
21-- weights just exceeding the root node capacity. This ensures that the tasks in the critical path
22-- completely 'covers' the root capacity.
23-- Typically, every node represents a point in time on some task where it transitioned from
24-- idle to active state.
25--
26-- Example usage on traces with Linux sched information:
27-- ```
28-- -- Compute the userspace critical path from every task sleep.
29-- SELECT * FROM
30--   critical_path_intervals!(
31--   _wakeup_userspace_edges,
32--   (SELECT id AS root_node_id, prev_id - id FROM _wakeup_graph WHERE prev_id IS NOT NULL));
33-- ```
34CREATE PERFETTO MACRO _critical_path(
35    -- A table/view/subquery corresponding to a directed graph on which the
36    -- reachability search should be performed. This table must have the columns
37    -- "source_node_id", "dest_node_id" and "edge_weight" corresponding to the two nodes on
38    -- either end of the edges in the graph and the edge weight.
39    --
40    -- Note: the columns must contain uint32 similar to ids in trace processor
41    -- tables (i.e. the values should be relatively dense and close to zero). The
42    -- implementation makes assumptions on this for performance reasons and, if
43    -- this criteria is not, can lead to enormous amounts of memory being
44    -- allocated.
45    -- An edge weight is the absolute difference between the node ids forming the edge.
46    graph_table TableOrSubQuery,
47    -- A table/view/subquery corresponding to start nodes to |graph_table| which will be the
48    -- roots of the reachability trees. This table must have the columns
49    -- "root_node_id" and "capacity" corresponding to the starting node id and the capacity
50    -- of the root node to contain edge weights.
51    --
52    -- Note: the columns must contain uint32 similar to ids in trace processor
53    -- tables (i.e. the values should be relatively dense and close to zero). The
54    -- implementation makes assumptions on this for performance reasons and, if
55    -- this criteria is not, can lead to enormous amounts of memory being
56    -- allocated.
57    root_table TableOrSubQuery
58)
59-- The returned table has the schema (root_id LONG, id LONG, parent_id LONG).
60-- |root_id| is the id of the root where the critical path computation started.
61-- |id| is the id of a node in the critical path and |parent_id| is the predecessor of |id|.
62RETURNS TableOrSubQuery AS
63(
64  WITH
65    _edges AS (
66      SELECT
67        source_node_id,
68        dest_node_id,
69        edge_weight
70      FROM $graph_table
71    ),
72    _roots AS (
73      SELECT
74        root_node_id,
75        capacity AS root_target_weight
76      FROM $root_table
77    ),
78    _search_bounds AS (
79      SELECT
80        min(root_node_id - root_target_weight) AS min_wakeup,
81        max(root_node_id + root_target_weight) AS max_wakeup
82      FROM _roots
83    ),
84    _graph AS (
85      SELECT
86        source_node_id,
87        coalesce(dest_node_id, source_node_id) AS dest_node_id,
88        edge_weight
89      FROM _edges, _search_bounds
90      WHERE
91        source_node_id BETWEEN min_wakeup AND max_wakeup AND source_node_id IS NOT NULL
92    )
93  SELECT DISTINCT
94    root_node_id AS root_id,
95    parent_node_id AS parent_id,
96    node_id AS id
97  FROM graph_reachable_weight_bounded_dfs !(_graph, _roots, 1) AS cr
98);
99
100-- Flattens overlapping tasks within a critical path and flattens overlapping critical paths.
101CREATE PERFETTO MACRO _critical_path_to_intervals(
102    critical_path_table TableOrSubquery,
103    node_table TableOrSubquery
104)
105RETURNS TableOrSubquery AS
106(
107  WITH
108    flat_tasks AS (
109      SELECT
110        node.ts,
111        cr.root_id,
112        cr.id,
113        lead(node.ts) OVER (PARTITION BY cr.root_id ORDER BY cr.id) - node.ts AS dur
114      FROM $critical_path_table AS cr
115      JOIN $node_table AS node
116        USING (id)
117    ),
118    span_starts AS (
119      SELECT
120        max(cr.ts, idle.ts - idle_dur) AS ts,
121        idle.ts AS idle_end_ts,
122        cr.ts + cr.dur AS cr_end_ts,
123        cr.id,
124        cr.root_id
125      FROM flat_tasks AS cr
126      JOIN $node_table AS idle
127        ON cr.root_id = idle.id
128    )
129  SELECT
130    ts,
131    min(cr_end_ts, idle_end_ts) - ts AS dur,
132    id,
133    root_id
134  FROM span_starts
135  WHERE
136    min(idle_end_ts, cr_end_ts) - ts > 0
137);
138
139-- Computes critical paths, the dependency graph of a task and returns a flattened view suitable
140-- for displaying in a UI track without any overlapping intervals.
141-- See the _critical_path MACRO above.
142--
143-- Example usage on traces with Linux sched information:
144-- ```
145-- -- Compute the userspace critical path from every task sleep.
146-- SELECT * FROM
147--   critical_path_intervals!(
148--   _wakeup_userspace_edges,
149--   (SELECT id AS root_node_id, prev_id - id FROM _wakeup_graph WHERE prev_id IS NOT NULL),
150--  _wakeup_intervals);
151-- ```
152CREATE PERFETTO MACRO _critical_path_intervals(
153    -- A table/view/subquery corresponding to a directed graph on which the
154    -- reachability search should be performed. This table must have the columns
155    -- "source_node_id", "dest_node_id" and "edge_weight" corresponding to the two nodes on
156    -- either end of the edges in the graph and the edge weight.
157    --
158    -- Note: the columns must contain uint32 similar to ids in trace processor
159    -- tables (i.e. the values should be relatively dense and close to zero). The
160    -- implementation makes assumptions on this for performance reasons and, if
161    -- this criteria is not, can lead to enormous amounts of memory being
162    -- allocated.
163    -- An edge weight is the absolute difference between the node ids forming the edge.
164    graph_table TableOrSubQuery,
165    -- A table/view/subquery corresponding to start nodes to |graph_table| which will be the
166    -- roots of the reachability trees. This table must have the columns
167    -- "root_node_id" and "capacity" corresponding to the starting node id and the capacity
168    -- of the root node to contain edge weights.
169    --
170    -- Note: the columns must contain uint32 similar to ids in trace processor
171    -- tables (i.e. the values should be relatively dense and close to zero). The
172    -- implementation makes assumptions on this for performance reasons and, if
173    -- this criteria is not, can lead to enormous amounts of memory being
174    -- allocated.
175    root_table TableOrSubQuery,
176    -- A table/view/subquery corresponding to the idle to active transition points on a task.
177    -- This table must have the columns, "id", "ts", "dur" and "idle_dur". ts and dur is the
178    -- timestamp when the task became active and how long it was active for respectively. idle_dur
179    -- is the duration it was idle for before it became active at "ts".
180    --
181    -- Note: the columns must contain uint32 similar to ids in trace processor
182    -- tables (i.e. the values should be relatively dense and close to zero). The
183    -- implementation makes assumptions on this for performance reasons and, if
184    -- this criteria is not, can lead to enormous amounts of memory being
185    -- allocated.
186    -- There should be one row for every node id encountered in the |graph_table|.
187    interval_table TableOrSubQuery
188)
189-- The returned table has the schema (id LONG, ts TIMESTAMP, dur DURATION, idle_dur LONG).
190-- |root_node_id| is the id of the starting node under which this edge was encountered.
191-- |node_id| is the id of the node from the input graph and |parent_node_id|
192-- is the id of the node which was the first encountered predecessor in a DFS
193-- search of the graph.
194RETURNS TableOrSubQuery AS
195(
196  WITH
197    _critical_path_nodes AS (
198      SELECT
199        root_id,
200        id
201      FROM _critical_path!($graph_table, $root_table)
202    )
203  SELECT
204    root_id,
205    id,
206    ts,
207    dur
208  FROM _critical_path_to_intervals !(_critical_path_nodes, $interval_table)
209  UNION ALL
210  SELECT
211    node.id AS root_id,
212    node.id,
213    node.ts,
214    node.dur
215  FROM $interval_table AS node
216  JOIN $root_table
217    ON root_node_id = id
218);
219