• 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
16INCLUDE PERFETTO MODULE graphs.dominator_tree;
17
18-- Excluding following types from the graph as they share objects' ownership
19-- with their real (more interesting) owners and will mask their idom to be the
20-- "super root".
21CREATE PERFETTO TABLE _ref_type_ids AS
22SELECT id AS type_id FROM heap_graph_class
23WHERE kind IN (
24  'KIND_FINALIZER_REFERENCE',
25  'KIND_PHANTOM_REFERENCE',
26  'KIND_SOFT_REFERENCE',
27  'KIND_WEAK_REFERENCE');
28
29CREATE PERFETTO TABLE _excluded_refs AS
30SELECT ref.id
31  FROM _ref_type_ids
32  JOIN heap_graph_object robj USING (type_id)
33  JOIN heap_graph_reference ref USING (reference_set_id)
34WHERE ref.field_name = 'java.lang.ref.Reference.referent'
35ORDER BY ref.id;
36
37-- The assigned id of the "super root".
38-- Since a Java heap graph is a "forest" structure, we need to add a imaginary
39-- "super root" node which connects all the roots of the forest into a single
40-- connected component, so that the dominator tree algorithm can be performed.
41CREATE PERFETTO FUNCTION memory_heap_graph_super_root_fn()
42-- The assigned id of the "super root".
43RETURNS INT AS
44SELECT max(id) + 1 FROM heap_graph_object;
45
46CREATE PERFETTO VIEW _dominator_compatible_heap_graph AS
47SELECT
48  ref.owner_id AS source_node_id,
49  ref.owned_id AS dest_node_id
50FROM heap_graph_reference ref
51JOIN heap_graph_object source_node ON ref.owner_id = source_node.id
52WHERE source_node.reachable
53  AND ref.id NOT IN _excluded_refs
54  AND ref.owned_id IS NOT NULL
55UNION ALL
56SELECT
57  (SELECT memory_heap_graph_super_root_fn()) as source_node_id,
58  id AS dest_node_id
59FROM heap_graph_object
60WHERE root_type IS NOT NULL;
61
62CREATE PERFETTO TABLE _heap_graph_dominator_tree AS
63SELECT
64  node_id AS id,
65  dominator_node_id AS idom_id
66FROM graph_dominator_tree!(
67  _dominator_compatible_heap_graph,
68  (SELECT memory_heap_graph_super_root_fn())
69)
70-- Excluding the imaginary root.
71WHERE dominator_node_id IS NOT NULL
72-- Ordering by idom_id so queries below are faster when joining on idom_id.
73-- TODO(lalitm): support create index for Perfetto tables.
74ORDER BY idom_id;
75
76CREATE PERFETTO TABLE _heap_graph_dominator_tree_depth AS
77WITH RECURSIVE _tree_visitor(id, depth) AS (
78  -- Let the super root have depth 0.
79  SELECT id, 1 AS depth
80  FROM _heap_graph_dominator_tree
81  WHERE idom_id IN (SELECT memory_heap_graph_super_root_fn())
82  UNION ALL
83  SELECT child.id, parent.depth + 1
84  FROM _heap_graph_dominator_tree child
85  JOIN _tree_visitor parent ON child.idom_id = parent.id
86)
87SELECT * FROM _tree_visitor
88ORDER BY id;
89
90-- A performance note: we need 3 memoize functions because EXPERIMENTAL_MEMOIZE
91-- limits the function to return only 1 int.
92-- This means the exact same "memoized dfs pass" on the tree is done 3 times, so
93-- it takes 3x the time taken by only doing 1 pass. Doing only 1 pass would be
94-- possible if EXPERIMENTAL_MEMOIZE could return more than 1 int.
95
96CREATE PERFETTO FUNCTION _subtree_obj_count(id INT)
97RETURNS INT AS
98SELECT 1 + IFNULL((
99  SELECT
100    SUM(_subtree_obj_count(child.id))
101  FROM _heap_graph_dominator_tree child
102  WHERE child.idom_id = $id
103), 0);
104SELECT EXPERIMENTAL_MEMOIZE('_subtree_obj_count');
105
106CREATE PERFETTO FUNCTION _subtree_size_bytes(id INT)
107RETURNS INT AS
108SELECT (
109  SELECT self_size
110  FROM heap_graph_object
111  WHERE heap_graph_object.id = $id
112) +
113IFNULL((
114  SELECT
115    SUM(_subtree_size_bytes(child.id))
116  FROM _heap_graph_dominator_tree child
117  WHERE child.idom_id = $id
118), 0);
119SELECT EXPERIMENTAL_MEMOIZE('_subtree_size_bytes');
120
121CREATE PERFETTO FUNCTION _subtree_native_size_bytes(id INT)
122RETURNS INT AS
123SELECT (
124  SELECT native_size
125  FROM heap_graph_object
126  WHERE heap_graph_object.id = $id
127) +
128IFNULL((
129  SELECT
130    SUM(_subtree_native_size_bytes(child.id))
131  FROM _heap_graph_dominator_tree child
132  WHERE child.idom_id = $id
133), 0);
134SELECT EXPERIMENTAL_MEMOIZE('_subtree_native_size_bytes');
135
136-- All reachable heap graph objects, their immediate dominators and summary of
137-- their dominated sets.
138-- The heap graph dominator tree is calculated by stdlib graphs.dominator_tree.
139-- Each reachable object is a node in the dominator tree, their immediate
140-- dominator is their parent node in the tree, and their dominated set is all
141-- their descendants in the tree. All size information come from the
142-- heap_graph_object prelude table.
143CREATE PERFETTO TABLE memory_heap_graph_dominator_tree (
144  -- Heap graph object id.
145  id INT,
146  -- Immediate dominator object id of the object.
147  idom_id INT,
148  -- Count of all objects dominated by this object, self inclusive.
149  dominated_obj_count INT,
150  -- Total self_size of all objects dominated by this object, self inclusive.
151  dominated_size_bytes INT,
152  -- Total native_size of all objects dominated by this object, self inclusive.
153  dominated_native_size_bytes INT,
154  -- Depth of the object in the dominator tree. Depth of root objects are 1.
155  depth INT
156) AS
157SELECT
158  t.id,
159  t.idom_id,
160  _subtree_obj_count(t.id) AS dominated_obj_count,
161  _subtree_size_bytes(t.id) AS dominated_size_bytes,
162  _subtree_native_size_bytes(t.id) AS dominated_native_size_bytes,
163  d.depth
164FROM _heap_graph_dominator_tree t
165JOIN _heap_graph_dominator_tree_depth d USING(id)
166ORDER BY id;
167