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-- Given a table containing a directed flow-graph and an entry node, computes 17-- the "dominator tree" for the graph. See [1] for an explanation of what a 18-- dominator tree is. 19-- 20-- [1] https://en.wikipedia.org/wiki/Dominator_(graph_theory) 21-- 22-- Example usage on traces containing heap graphs: 23-- ``` 24-- CREATE PERFETTO VIEW dominator_compatible_heap_graph AS 25-- -- Extract the edges from the heap graph which correspond to references 26-- -- between objects. 27-- SELECT 28-- owner_id AS source_node_id, 29-- owned_id as dest_node_id 30-- FROM heap_graph_reference 31-- JOIN heap_graph_object owner on heap_graph_reference.owner_id = owner.id 32-- WHERE owned_id IS NOT NULL AND owner.reachable 33-- UNION ALL 34-- -- Since a Java heap graph is a "forest" structure, we need to add a dummy 35-- -- "root" node which connects all the roots of the forest into a single 36-- -- connected component. 37-- SELECT 38-- (SELECT max(id) + 1 FROM heap_graph_object) as source_node_id, 39-- id 40-- FROM heap_graph_object 41-- WHERE root_type IS NOT NULL; 42-- 43-- SELECT * 44-- FROM graph_dominator_tree!( 45-- dominator_compatible_heap_graph, 46-- (SELECT max(id) + 1 FROM heap_graph_object) 47-- ); 48-- ``` 49CREATE PERFETTO MACRO graph_dominator_tree( 50 -- A table/view/subquery corresponding to a directed flow-graph on which the 51 -- dominator tree should be computed. This table must have the columns 52 -- "source_node_id" and "dest_node_id" corresponding to the two nodes on 53 -- either end of the edges in the graph. 54 -- 55 -- Note: the columns must contain uint32 similar to ids in trace processor 56 -- tables (i.e. the values should be relatively dense and close to zero). The 57 -- implementation makes assumptions on this for performance reasons and, if 58 -- this criteria is not, can lead to enormous amounts of memory being 59 -- allocated. 60 -- 61 -- Note: this means that the graph *must* be a single fully connected 62 -- component with |root_node_id| (see below) being the "entry node" for this 63 -- component. Specifically, all nodes *must* be reachable by following paths 64 -- from the root node. Failing to adhere to this property will result in 65 -- undefined behaviour. 66 -- 67 -- If working with a "forest"-like structure, a dummy node should be added which 68 -- links all the roots of the forest together into a single component; an example 69 -- of this can be found in the heap graph example query above. 70 graph_table TableOrSubquery, 71 -- The entry node to |graph_table| which will be the root of the dominator 72 -- tree. 73 root_node_id Expr 74) 75-- The returned table has the schema (node_id LONG, dominator_node_id LONG). 76-- |node_id| is the id of the node from the input graph and |dominator_node_id| 77-- is the id of the node in the input flow-graph which is the "dominator" of 78-- |node_id|. 79RETURNS TableOrSubquery AS 80( 81 -- Rename the generic columns of __intrinsic_table_ptr to the actual columns. 82 SELECT 83 c0 AS node_id, 84 c1 AS dominator_node_id 85 FROM __intrinsic_table_ptr( 86 ( 87 -- Aggregate function to perform a DFS on the nodes on the input graph. 88 SELECT 89 __intrinsic_dominator_tree(g.source_node_id, g.dest_node_id, $root_node_id) 90 FROM $graph_table AS g 91 ) 92 ) 93 -- Bind the dynamic columns in the |__intrinsic_table_ptr| to the columns of 94 -- the dominator tree table. 95 WHERE 96 __intrinsic_table_ptr_bind(c0, 'node_id') 97 AND __intrinsic_table_ptr_bind(c1, 'dominator_node_id') 98); 99