tp: add some macros and tables for operating on heap graphs
This prepares for the addition of flamegraphs on top of heap graphs
using SQL queries.
Change-Id: Ie579e767eea21bfa5881b2c45519bc3387512813
diff --git a/Android.bp b/Android.bp
index a16b10c..7ebf1fb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13122,8 +13122,12 @@
"src/trace_processor/perfetto_sql/stdlib/android/io.sql",
"src/trace_processor/perfetto_sql/stdlib/android/job_scheduler.sql",
"src/trace_processor/perfetto_sql/stdlib/android/memory/dmabuf.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/class_tree.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_class_tree.sql",
"src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_tree.sql",
"src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/excluded_refs.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/helpers.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/raw_dominator_tree.sql",
"src/trace_processor/perfetto_sql/stdlib/android/memory/process.sql",
"src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql",
"src/trace_processor/perfetto_sql/stdlib/android/network_packets.sql",
diff --git a/BUILD b/BUILD
index 2423b1e..55b6ec0 100644
--- a/BUILD
+++ b/BUILD
@@ -2534,8 +2534,12 @@
perfetto_filegroup(
name = "src_trace_processor_perfetto_sql_stdlib_android_memory_heap_graph_heap_graph",
srcs = [
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/class_tree.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_class_tree.sql",
"src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_tree.sql",
"src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/excluded_refs.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/helpers.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/raw_dominator_tree.sql",
],
)
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/BUILD.gn
index 51eb1a4..c368232 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/BUILD.gn
@@ -16,7 +16,11 @@
perfetto_sql_source_set("heap_graph") {
sources = [
+ "class_tree.sql",
+ "dominator_class_tree.sql",
"dominator_tree.sql",
"excluded_refs.sql",
+ "helpers.sql",
+ "raw_dominator_tree.sql",
]
}
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/class_tree.sql b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/class_tree.sql
new file mode 100644
index 0000000..6616af5
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/class_tree.sql
@@ -0,0 +1,50 @@
+--
+-- Copyright 2024 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed ON an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+INCLUDE PERFETTO MODULE android.memory.heap_graph.excluded_refs;
+INCLUDE PERFETTO MODULE android.memory.heap_graph.helpers;
+INCLUDE PERFETTO MODULE graphs.search;
+
+-- Converts the heap graph into a tree by performing a BFS on the graph from
+-- the roots. This basically ends up with all paths being the shortest path
+-- from the root to the node (with lower ids being picked in the case of ties).
+CREATE PERFETTO TABLE _heap_graph_object_min_depth_tree AS
+SELECT node_id AS id, parent_node_id AS parent_id
+FROM graph_reachable_bfs!(
+ (
+ SELECT owner_id AS source_node_id, owned_id AS dest_node_id
+ FROM heap_graph_reference ref
+ WHERE ref.id NOT IN _excluded_refs AND ref.owned_id IS NOT NULL
+ ORDER BY ref.owned_id
+ ),
+ (
+ SELECT id AS node_id
+ FROM heap_graph_object
+ WHERE root_type IS NOT NULL
+ )
+)
+ORDER BY id;
+
+CREATE PERFETTO TABLE _heap_graph_path_hashes as
+SELECT *
+FROM _heap_graph_type_path_hash!(_heap_graph_object_min_depth_tree);
+
+CREATE PERFETTO TABLE _heap_graph_path_hashes_aggregated as
+SELECT *
+FROM _heap_graph_path_hash_aggregate!(_heap_graph_path_hashes);
+
+CREATE PERFETTO TABLE _heap_graph_class_tree AS
+SELECT *
+FROM _heap_graph_path_hashes_to_class_tree!(_heap_graph_path_hashes_aggregated);
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_class_tree.sql b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_class_tree.sql
new file mode 100644
index 0000000..f0d9eea
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_class_tree.sql
@@ -0,0 +1,34 @@
+--
+-- Copyright 2024 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed ON an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+INCLUDE PERFETTO MODULE android.memory.heap_graph.helpers;
+INCLUDE PERFETTO MODULE android.memory.heap_graph.raw_dominator_tree;
+
+CREATE PERFETTO TABLE _heap_graph_dominator_path_hashes as
+SELECT *
+FROM _heap_graph_type_path_hash!((
+ SELECT id, idom_id AS parent_id
+ FROM _raw_heap_graph_dominator_tree
+));
+
+CREATE PERFETTO TABLE _heap_graph_dominator_path_hashes_aggregated as
+SELECT *
+FROM _heap_graph_path_hash_aggregate!(_heap_graph_dominator_path_hashes);
+
+CREATE PERFETTO TABLE _heap_graph_dominator_class_tree AS
+SELECT *
+FROM _heap_graph_path_hashes_to_class_tree!(
+ _heap_graph_dominator_path_hashes_aggregated
+);
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_tree.sql b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_tree.sql
index 00e4d41..6c12783 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_tree.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/dominator_tree.sql
@@ -13,47 +13,8 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
-INCLUDE PERFETTO MODULE android.memory.heap_graph.excluded_refs;
-INCLUDE PERFETTO MODULE graphs.dominator_tree;
INCLUDE PERFETTO MODULE graphs.scan;
-
--- The assigned id of the "super root".
--- Since a Java heap graph is a "forest" structure, we need to add a imaginary
--- "super root" node which connects all the roots of the forest into a single
--- connected component, so that the dominator tree algorithm can be performed.
-CREATE PERFETTO FUNCTION _heap_graph_super_root_fn()
--- The assigned id of the "super root".
-RETURNS INT AS
-SELECT id + 1
-FROM heap_graph_object
-ORDER BY id DESC
-LIMIT 1;
-
-CREATE PERFETTO VIEW _dominator_compatible_heap_graph AS
-SELECT
- ref.owner_id AS source_node_id,
- ref.owned_id AS dest_node_id
-FROM heap_graph_reference ref
-JOIN heap_graph_object source_node ON ref.owner_id = source_node.id
-WHERE source_node.reachable
- AND ref.id NOT IN _excluded_refs
- AND ref.owned_id IS NOT NULL
-UNION ALL
-SELECT
- (SELECT _heap_graph_super_root_fn()) as source_node_id,
- id AS dest_node_id
-FROM heap_graph_object
-WHERE root_type IS NOT NULL;
-
-CREATE PERFETTO TABLE _raw_heap_graph_dominator_tree AS
-SELECT node_id AS id, dominator_node_id as idom_id
-FROM graph_dominator_tree!(
- _dominator_compatible_heap_graph,
- (SELECT _heap_graph_super_root_fn())
-)
--- Excluding the imaginary root.
-WHERE dominator_node_id IS NOT NULL
-ORDER BY id;
+INCLUDE PERFETTO MODULE android.memory.heap_graph.raw_dominator_tree;
CREATE PERFETTO TABLE _heap_graph_dominator_tree_bottom_up_scan AS
SELECT *
@@ -61,7 +22,7 @@
(
SELECT id AS source_node_id, idom_id AS dest_node_id
FROM _raw_heap_graph_dominator_tree
- WHERE idom_id != _heap_graph_super_root_fn()
+ WHERE idom_id IS NOT NULL
),
(
SELECT
@@ -102,12 +63,12 @@
(
SELECT idom_id AS source_node_id, id AS dest_node_id
FROM _raw_heap_graph_dominator_tree
- WHERE idom_id != _heap_graph_super_root_fn()
+ WHERE idom_id IS NOT NULL
),
(
SELECT id, 1 AS depth
FROM _raw_heap_graph_dominator_tree
- WHERE idom_id = _heap_graph_super_root_fn()
+ WHERE idom_id IS NULL
),
(depth),
(SELECT t.id, t.depth + 1 AS depth FROM $table t)
@@ -139,7 +100,7 @@
) AS
SELECT
r.id,
- IIF(r.idom_id = _heap_graph_super_root_fn(), NULL, r.idom_id) AS idom_id,
+ r.idom_id AS idom_id,
d.subtree_count AS dominated_obj_count,
d.subtree_size_bytes AS dominated_size_bytes,
d.subtree_native_size_bytes AS dominated_native_size_bytes,
@@ -147,5 +108,5 @@
FROM _raw_heap_graph_dominator_tree r
JOIN _heap_graph_dominator_tree_bottom_up_scan d USING(id)
JOIN _heap_graph_dominator_tree_top_down_scan t USING (id)
-WHERE r.id != _heap_graph_super_root_fn()
+WHERE r.id IS NOT NULL
ORDER BY id;
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/helpers.sql b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/helpers.sql
new file mode 100644
index 0000000..ba6a7b1
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/helpers.sql
@@ -0,0 +1,146 @@
+--
+-- Copyright 2024 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed ON an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+INCLUDE PERFETTO MODULE graphs.scan;
+
+-- Given a table containing a "tree-ified" heap graph object table (i.e.
+-- by using a dominator tree or shortest path algorithm), computes a hash of
+-- the path from the root to each node in the graph based on class names.
+--
+-- This allows an SQL aggregation of all nodes which have the same hash to
+-- build a "class-tree" instead of the object tree.
+CREATE PERFETTO MACRO _heap_graph_type_path_hash(tab TableOrSubquery)
+RETURNS TableOrSubquery
+AS (
+ SELECT id, path_hash, parent_path_hash
+ FROM _graph_scan!(
+ (
+ SELECT parent_id AS source_node_id, id AS dest_node_id
+ FROM $tab
+ WHERE parent_id IS NOT NULL
+ ),
+ (
+ SELECT
+ t.id,
+ o.type_id as parent_type_id,
+ HASH(
+ o.upid,
+ o.graph_sample_ts,
+ o.type_id,
+ IFNULL(o.root_type, '')
+ ) AS path_hash,
+ 0 AS parent_path_hash
+ FROM $tab t
+ JOIN heap_graph_object o USING (id)
+ WHERE t.parent_id IS NULL
+ ),
+ (parent_type_id, path_hash, parent_path_hash),
+ (
+ SELECT
+ t.id,
+ o.type_id as parent_type_id,
+ IIF(
+ o.type_id = t.parent_type_id,
+ t.path_hash,
+ HASH(t.path_hash, o.type_id)
+ ) AS path_hash,
+ IIF(
+ o.type_id = t.parent_type_id,
+ t.parent_path_hash,
+ t.path_hash
+ ) AS parent_path_hash
+ FROM $table t
+ JOIN heap_graph_object o USING (id)
+ )
+ )
+ ORDER BY id
+);
+
+-- Given a table containing heap graph tree-table with path hashes computed
+-- (see _heap_graph_type_path_hash macro), aggregates together all nodes
+-- with the same hash and also splits out "native size" as a separate node under
+-- the nodes which contain the native size.
+CREATE PERFETTO MACRO _heap_graph_path_hash_aggregate(tab TableOrSubquery)
+RETURNS TableOrSubquery
+AS (
+ with x AS (
+ SELECT
+ o.graph_sample_ts,
+ o.upid,
+ path_hash,
+ parent_path_hash,
+ COALESCE(
+ c.deobfuscated_name || ' [' || o.root_type || ']',
+ c.name || ' [' || o.root_type || ']',
+ c.deobfuscated_name,
+ c.name
+ ) AS name,
+ COUNT() AS self_count,
+ SUM(o.self_size) AS self_size,
+ SUM(o.native_size > 0) AS self_native_count,
+ SUM(o.native_size) AS self_native_size
+ FROM $tab
+ JOIN heap_graph_object o USING (id)
+ JOIN heap_graph_class c ON o.type_id = c.id
+ GROUP BY path_hash
+ )
+ SELECT
+ graph_sample_ts,
+ upid,
+ HASH(path_hash, 'native', '') AS path_hash,
+ path_hash AS parent_path_hash,
+ '[native] ' || x.name AS name,
+ SUM(x.self_native_count) AS self_count,
+ SUM(x.self_native_size) AS self_size
+ FROM x
+ WHERE x.self_native_size > 0
+ GROUP BY path_hash
+ UNION ALL
+ SELECT
+ graph_sample_ts,
+ upid,
+ path_hash,
+ parent_path_hash,
+ name,
+ self_count,
+ self_size
+ FROM x
+ ORDER BY path_hash
+);
+
+-- Given a table containing heap graph tree-table aggregated by path hashes
+-- (see _heap_graph_path_hash_aggregate) computes the "class tree" by converting
+-- the path hashes to ids.
+--
+-- Note that |tab| *must* be a Perfetto (e.g. not a subquery) for this macro
+-- to work.
+CREATE PERFETTO MACRO _heap_graph_path_hashes_to_class_tree(tab TableOrSubquery)
+RETURNS TableOrSubquery
+AS (
+ SELECT
+ graph_sample_ts,
+ upid,
+ _auto_id AS id,
+ (
+ SELECT p._auto_id
+ FROM $tab p
+ WHERE c.parent_path_hash = p.path_hash
+ ) AS parent_id,
+ name,
+ self_count,
+ self_size
+ FROM $tab c
+ ORDER BY id
+);
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/raw_dominator_tree.sql b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/raw_dominator_tree.sql
new file mode 100644
index 0000000..b6d41fb
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/memory/heap_graph/raw_dominator_tree.sql
@@ -0,0 +1,61 @@
+--
+-- Copyright 2024 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+INCLUDE PERFETTO MODULE android.memory.heap_graph.excluded_refs;
+INCLUDE PERFETTO MODULE graphs.dominator_tree;
+
+-- The assigned id of the "super root".
+-- Since a Java heap graph is a "forest" structure, we need to add a imaginary
+-- "super root" node which connects all the roots of the forest into a single
+-- connected component, so that the dominator tree algorithm can be performed.
+CREATE PERFETTO FUNCTION _heap_graph_super_root_fn()
+-- The assigned id of the "super root".
+RETURNS INT AS
+SELECT id + 1
+FROM heap_graph_object
+ORDER BY id DESC
+LIMIT 1;
+
+CREATE PERFETTO VIEW _dominator_compatible_heap_graph AS
+SELECT
+ ref.owner_id AS source_node_id,
+ ref.owned_id AS dest_node_id
+FROM heap_graph_reference ref
+JOIN heap_graph_object source_node ON ref.owner_id = source_node.id
+WHERE source_node.reachable
+ AND ref.id NOT IN _excluded_refs
+ AND ref.owned_id IS NOT NULL
+UNION ALL
+SELECT
+ (SELECT _heap_graph_super_root_fn()) as source_node_id,
+ id AS dest_node_id
+FROM heap_graph_object
+WHERE root_type IS NOT NULL;
+
+CREATE PERFETTO TABLE _raw_heap_graph_dominator_tree AS
+SELECT
+ node_id AS id,
+ iif(
+ dominator_node_id = _heap_graph_super_root_fn(),
+ null,
+ dominator_node_id
+ ) as idom_id
+FROM graph_dominator_tree!(
+ _dominator_compatible_heap_graph,
+ (SELECT _heap_graph_super_root_fn())
+)
+-- Excluding the imaginary root.
+WHERE dominator_node_id IS NOT NULL
+ORDER BY id;