• 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-- sqlformat file off
17-- The case sensitivity of this file matters so don't format it which
18-- changes sensitivity.
19
20INCLUDE PERFETTO MODULE graphs.scan;
21
22CREATE PERFETTO MACRO _viz_flamegraph_hash_coalesce(col ColumnName)
23RETURNS Expr AS IFNULL($col, 0);
24
25-- For each frame in |tab|, returns a row containing the result of running
26-- all the filtering operations over that frame's name.
27CREATE PERFETTO MACRO _viz_flamegraph_prepare_filter(
28  tab TableOrSubquery,
29  show_stack Expr,
30  hide_stack Expr,
31  show_from_frame Expr,
32  hide_frame Expr,
33  pivot Expr,
34  impossible_stack_bits Expr,
35  grouping _ColumnNameList
36)
37RETURNS TableOrSubquery
38AS (
39  SELECT
40    *,
41    IIF($hide_stack, $impossible_stack_bits, $show_stack) AS stackBits,
42    $show_from_frame As showFromFrameBits,
43    $hide_frame = 0 AS showFrame,
44    $pivot AS isPivot,
45    HASH(
46      name,
47      __intrinsic_token_apply!(_viz_flamegraph_hash_coalesce, $grouping)
48    ) AS groupingHash
49  FROM $tab
50  ORDER BY id
51);
52
53-- Walks the forest from root to leaf and performs the following operations:
54--  1) removes frames which were filtered out
55--  2) make any pivot nodes become the roots
56--  3) computes whether the stack as a whole should be retained or not
57CREATE PERFETTO MACRO _viz_flamegraph_filter_frames(
58  source TableOrSubquery,
59  show_from_frame_bits Expr
60)
61RETURNS TableOrSubquery
62AS (
63  WITH edges AS (
64    SELECT parentId AS source_node_id, id AS dest_node_id
65    FROM $source
66    WHERE parentId IS NOT NULL
67  ),
68  inits AS (
69    SELECT
70      id,
71      IIF(
72        showFrame AND showFromFrameBits = $show_from_frame_bits,
73        id,
74        NULL
75      ) AS filteredId,
76      NULL AS filteredParentId,
77      NULL AS filteredUnpivotedParentId,
78      IIF(
79        showFrame,
80        showFromFrameBits,
81        0
82      ) AS showFromFrameBits,
83      IIF(
84        showFrame AND showFromFrameBits = $show_from_frame_bits,
85        stackBits,
86        0
87      ) AS stackBits
88    FROM $source
89    WHERE parentId IS NULL
90  )
91  SELECT
92    g.filteredId AS id,
93    g.filteredParentId AS parentId,
94    g.filteredUnpivotedParentId AS unpivotedParentId,
95    g.stackBits,
96    SUM(t.value) AS value
97  FROM _graph_scan!(
98    edges,
99    inits,
100    (filteredId, filteredParentId, filteredUnpivotedParentId, showFromFrameBits, stackBits),
101    (
102      SELECT
103        t.id,
104        IIF(
105          x.showFrame AND (t.showFromFrameBits | x.showFromFrameBits) = $show_from_frame_bits,
106          t.id,
107          t.filteredId
108        ) AS filteredId,
109        IIF(
110          x.showFrame AND (t.showFromFrameBits | x.showFromFrameBits) = $show_from_frame_bits,
111          IIF(x.isPivot, NULL, t.filteredId),
112          t.filteredParentId
113        ) AS filteredParentId,
114        IIF(
115          x.showFrame AND (t.showFromFrameBits | x.showFromFrameBits) = $show_from_frame_bits,
116          t.filteredId,
117          t.filteredParentId
118        ) AS filteredUnpivotedParentId,
119        IIF(
120          x.showFrame,
121          (t.showFromFrameBits | x.showFromFrameBits),
122          t.showFromFrameBits
123        ) AS showFromFrameBits,
124        IIF(
125          x.showFrame AND (t.showFromFrameBits | x.showFromFrameBits) = $show_from_frame_bits,
126          (t.stackBits | x.stackBits),
127          t.stackBits
128        ) AS stackBits
129      FROM $table t
130      JOIN $source x USING (id)
131    )
132  ) g
133  JOIN $source t USING (id)
134  WHERE filteredId IS NOT NULL
135  GROUP BY filteredId
136  ORDER BY filteredId
137);
138
139-- Walks the forest from leaves to root and does the following:
140--   1) removes nodes whose stacks are filtered out
141--   2) computes the cumulative value for each node (i.e. the sum of the self
142--      value of the node and all descendants).
143CREATE PERFETTO MACRO _viz_flamegraph_accumulate(
144  filtered TableOrSubquery,
145  showStackBits Expr
146)
147RETURNS TableOrSubquery
148AS (
149  WITH edges AS (
150    SELECT id AS source_node_id, parentId AS dest_node_id
151    FROM $filtered
152    WHERE parentId IS NOT NULL
153  ), inits AS (
154    SELECT f.id, f.value AS cumulativeValue
155    FROM $filtered f
156    LEFT JOIN $filtered c ON c.parentId = f.id
157    WHERE c.id IS NULL AND f.stackBits = $showStackBits
158  )
159  SELECT id, cumulativeValue
160  FROM _graph_aggregating_scan!(
161    edges,
162    inits,
163    (cumulativeValue),
164    (
165      SELECT
166        x.id,
167        x.childValue + IIF(
168          t.stackBits = $showStackBits,
169          t.value,
170          0
171        ) AS cumulativeValue
172      FROM (
173        SELECT id, SUM(cumulativeValue) AS childValue
174        FROM $table
175        GROUP BY id
176      ) x
177      JOIN $filtered t USING (id)
178    )
179  )
180  ORDER BY id
181);
182
183CREATE PERFETTO MACRO _viz_flamegraph_s_prefix(col ColumnName)
184RETURNS Expr AS s.$col;
185
186-- Propogates the cumulative value of the pivot nodes to the roots
187-- and computes the "fingerprint" of the path.
188CREATE PERFETTO MACRO _viz_flamegraph_upwards_hash(
189  source TableOrSubquery,
190  filtered TableOrSubquery,
191  accumulated TableOrSubquery,
192  grouping _ColumnNameList,
193  grouped _ColumnNameList
194)
195RETURNS TableOrSubquery
196AS (
197  WITH edges AS (
198    SELECT id AS source_node_id, unpivotedParentId AS dest_node_id
199    FROM $filtered
200    WHERE unpivotedParentId IS NOT NULL
201  ),
202  inits AS (
203    SELECT
204      f.id,
205      HASH(-1, s.groupingHash) AS hash,
206      NULL AS parentHash,
207      -1 AS depth,
208      a.cumulativeValue
209    FROM $filtered f
210    JOIN $source s USING (id)
211    JOIN $accumulated a USING (id)
212    WHERE s.isPivot AND a.cumulativeValue > 0
213  )
214  SELECT
215    g.id,
216    g.hash,
217    g.parentHash,
218    g.depth,
219    s.name,
220    __intrinsic_token_apply!(_viz_flamegraph_s_prefix, $grouping),
221    __intrinsic_token_apply!(_viz_flamegraph_s_prefix, $grouped),
222    f.value,
223    g.cumulativeValue
224  FROM _graph_scan!(
225    edges,
226    inits,
227    (hash, parentHash, depth, cumulativeValue),
228    (
229      SELECT
230        t.id,
231        HASH(t.hash, x.groupingHash) AS hash,
232        t.hash AS parentHash,
233        t.depth - 1 AS depth,
234        t.cumulativeValue
235      FROM $table t
236      JOIN $source x USING (id)
237    )
238  ) g
239  JOIN $source s USING (id)
240  JOIN $filtered f USING (id)
241);
242
243-- Computes the "fingerprint" of the path by walking from the laves
244-- to the root.
245CREATE PERFETTO MACRO _viz_flamegraph_downwards_hash(
246  source TableOrSubquery,
247  filtered TableOrSubquery,
248  accumulated TableOrSubquery,
249  grouping _ColumnNameList,
250  grouped _ColumnNameList,
251  showDownward Expr
252)
253RETURNS TableOrSubquery
254AS (
255  WITH
256    edges AS (
257      SELECT parentId AS source_node_id, id AS dest_node_id
258      FROM $filtered
259      WHERE parentId IS NOT NULL
260    ),
261    inits AS (
262      SELECT
263        f.id,
264        HASH(1, s.groupingHash) AS hash,
265        NULL AS parentHash,
266        1 AS depth
267      FROM $filtered f
268      JOIN $source s USING (id)
269      WHERE f.parentId IS NULL AND $showDownward
270    )
271  SELECT
272    g.id,
273    g.hash,
274    g.parentHash,
275    g.depth,
276    s.name,
277    __intrinsic_token_apply!(_viz_flamegraph_s_prefix, $grouping),
278    __intrinsic_token_apply!(_viz_flamegraph_s_prefix, $grouped),
279    f.value,
280    a.cumulativeValue
281  FROM _graph_scan!(
282    edges,
283    inits,
284    (hash, parentHash, depth),
285    (
286      SELECT
287        t.id,
288        HASH(t.hash, x.groupingHash) AS hash,
289        t.hash AS parentHash,
290        t.depth + 1 AS depth
291      FROM $table t
292      JOIN $source x USING (id)
293    )
294  ) g
295  JOIN $source s USING (id)
296  JOIN $filtered f USING (id)
297  JOIN $accumulated a USING (id)
298  ORDER BY hash
299);
300
301CREATE PERFETTO MACRO _col_list_id(a ColumnName)
302RETURNS Expr AS $a;
303
304-- Converts a table of hashes and paretn hashes into ids and parent
305-- ids, grouping all hashes together.
306CREATE PERFETTO MACRO _viz_flamegraph_merge_hashes(
307  hashed TableOrSubquery,
308  grouping _ColumnNameList,
309  grouped_agged_exprs _ColumnNameList
310)
311RETURNS TableOrSubquery
312AS (
313  SELECT
314    _auto_id AS id,
315    (
316      SELECT p._auto_id
317      FROM $hashed p
318      WHERE p.hash = c.parentHash
319      LIMIT 1
320    ) AS parentId,
321    depth,
322    name,
323    -- The grouping columns should be passed through as-is because the
324    -- hash took them into account: we would not merged any nodes where
325    -- the grouping columns were different.
326    __intrinsic_token_apply!(_col_list_id, $grouping),
327    __intrinsic_token_apply!(_col_list_id, $grouped_agged_exprs),
328    SUM(value) AS value,
329    SUM(cumulativeValue) AS cumulativeValue
330  FROM $hashed c
331  GROUP BY hash
332);
333
334-- Performs a "layout" of nodes in the flamegraph relative to their
335-- siblings.
336CREATE PERFETTO MACRO _viz_flamegraph_local_layout(
337  merged TableOrSubquery
338)
339RETURNS TableOrSubquery
340AS (
341  WITH partial_layout AS (
342    SELECT
343      id,
344      cumulativeValue,
345      SUM(cumulativeValue) OVER win AS xEnd
346    FROM $merged
347    WHERE cumulativeValue > 0
348    WINDOW win AS (
349      PARTITION BY parentId, depth
350      ORDER BY cumulativeValue DESC
351      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
352    )
353  )
354  SELECT id, xEnd - cumulativeValue as xStart, xEnd
355  FROM partial_layout
356  ORDER BY id
357);
358
359-- Walks the graph from root to leaf, propogating the layout of
360-- parents to their children.
361CREATE PERFETTO MACRO _viz_flamegraph_global_layout(
362  merged TableOrSubquery,
363  layout TableOrSubquery,
364  grouping _ColumnNameList,
365  grouped _ColumnNameList
366)
367RETURNS TableOrSubquery
368AS (
369  WITH edges AS (
370    SELECT parentId AS source_node_id, id AS dest_node_id
371    FROM $merged
372    WHERE parentId IS NOT NULL
373  ),
374  inits AS (
375    SELECT h.id, 1 AS rootDistance, l.xStart, l.xEnd
376    FROM $merged h
377    JOIN $layout l USING (id)
378    WHERE h.parentId IS NULL
379  )
380  SELECT
381    s.id,
382    IFNULL(s.parentId, -1) AS parentId,
383    IIF(s.name = '', 'unknown', s.name) AS name,
384    __intrinsic_token_apply!(_viz_flamegraph_s_prefix, $grouping),
385    __intrinsic_token_apply!(_viz_flamegraph_s_prefix, $grouped),
386    s.value AS selfValue,
387    s.cumulativeValue,
388    p.cumulativeValue AS parentCumulativeValue,
389    s.depth,
390    g.xStart,
391    g.xEnd
392  FROM _graph_scan!(
393    edges,
394    inits,
395    (rootDistance, xStart, xEnd),
396    (
397      SELECT
398        t.id,
399        t.rootDistance + 1 as rootDistance,
400        t.xStart + w.xStart AS xStart,
401        t.xStart + w.xEnd AS xEnd
402      FROM $table t
403      JOIN $layout w USING (id)
404    )
405  ) g
406  JOIN $merged s USING (id)
407  LEFT JOIN $merged p ON s.parentId = p.id
408  ORDER BY rootDistance, xStart
409);
410