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.hierarchy; 17 18INCLUDE PERFETTO MODULE graphs.scan; 19 20INCLUDE PERFETTO MODULE v8.jit; 21 22CREATE PERFETTO TABLE _callstack_spf_summary AS 23SELECT 24 id, 25 symbol_set_id, 26 ( 27 SELECT 28 id 29 FROM stack_profile_symbol AS s 30 WHERE 31 s.symbol_set_id = f.symbol_set_id 32 ORDER BY 33 id 34 LIMIT 1 35 ) AS min_symbol_id, 36 ( 37 SELECT 38 id 39 FROM stack_profile_symbol AS s 40 WHERE 41 s.symbol_set_id = f.symbol_set_id 42 ORDER BY 43 id DESC 44 LIMIT 1 45 ) AS max_symbol_id 46FROM stack_profile_frame AS f 47ORDER BY 48 id; 49 50CREATE PERFETTO TABLE _callstack_spc_raw_forest AS 51SELECT 52 c.id AS callsite_id, 53 s.id AS symbol_id, 54 iif(s.id IS f.max_symbol_id, c.parent_id, c.id) AS parent_callsite_id, 55 iif(s.id IS f.max_symbol_id, pf.min_symbol_id, s.id + 1) AS parent_symbol_id, 56 f.id AS frame_id, 57 jf.jit_code_id AS jit_code_id, 58 s.id IS f.min_symbol_id AS is_leaf 59FROM stack_profile_callsite AS c 60JOIN _callstack_spf_summary AS f 61 ON c.frame_id = f.id 62LEFT JOIN __intrinsic_jit_frame AS jf 63 ON jf.frame_id = f.id 64LEFT JOIN stack_profile_symbol AS s 65 USING (symbol_set_id) 66LEFT JOIN stack_profile_callsite AS p 67 ON c.parent_id = p.id 68LEFT JOIN _callstack_spf_summary AS pf 69 ON p.frame_id = pf.id 70ORDER BY 71 c.id; 72 73CREATE PERFETTO TABLE _callstack_spc_forest AS 74SELECT 75 c._auto_id AS id, 76 p._auto_id AS parent_id, 77 -- TODO(lalitm): consider demangling in a separate table as 78 -- demangling is suprisingly inefficient and is taking a 79 -- significant fraction of the runtime on big traces. 80 coalesce( 81 'JS: ' || iif(jsf.name = "", "(anonymous)", jsf.name) || ':' || jsf.line || ':' || jsf.col || ' [' || lower(jsc.tier) || ']', 82 'WASM: ' || wc.function_name || ' [' || lower(wc.tier) || ']', 83 'REGEXP: ' || rc.pattern, 84 'V8: ' || v8c.function_name, 85 'JIT: ' || jc.function_name, 86 demangle(coalesce(s.name, f.deobfuscated_name, f.name)), 87 coalesce(s.name, f.deobfuscated_name, f.name, '[Unknown]') 88 ) AS name, 89 f.mapping AS mapping_id, 90 s.source_file, 91 coalesce(jsf.line, s.line_number) AS line_number, 92 coalesce(jsf.col, 0) AS column_number, 93 c.callsite_id, 94 c.is_leaf AS is_leaf_function_in_callsite_frame 95FROM _callstack_spc_raw_forest AS c 96JOIN stack_profile_frame AS f 97 ON c.frame_id = f.id 98LEFT JOIN _v8_js_code AS jsc 99 USING (jit_code_id) 100LEFT JOIN v8_js_function AS jsf 101 USING (v8_js_function_id) 102LEFT JOIN _v8_internal_code AS v8c 103 USING (jit_code_id) 104LEFT JOIN _v8_wasm_code AS wc 105 USING (jit_code_id) 106LEFT JOIN _v8_regexp_code AS rc 107 USING (jit_code_id) 108LEFT JOIN __intrinsic_jit_code AS jc 109 ON c.jit_code_id = jc.id 110LEFT JOIN stack_profile_symbol AS s 111 ON c.symbol_id = s.id 112LEFT JOIN _callstack_spc_raw_forest AS p 113 ON p.callsite_id = c.parent_callsite_id AND p.symbol_id IS c.parent_symbol_id 114ORDER BY 115 c._auto_id; 116 117CREATE PERFETTO INDEX _callstack_spc_index ON _callstack_spc_forest(callsite_id); 118 119CREATE PERFETTO MACRO _callstacks_for_stack_profile_samples( 120 spc_samples TableOrSubquery 121) 122RETURNS TableOrSubquery AS 123( 124 SELECT 125 f.id, 126 f.parent_id, 127 f.callsite_id, 128 f.name, 129 m.name AS mapping_name, 130 f.source_file, 131 f.line_number, 132 f.is_leaf_function_in_callsite_frame 133 FROM _tree_reachable_ancestors_or_self!( 134 _callstack_spc_forest, 135 ( 136 SELECT f.id 137 FROM $spc_samples s 138 JOIN _callstack_spc_forest f USING (callsite_id) 139 WHERE f.is_leaf_function_in_callsite_frame 140 ) 141 ) AS g 142 JOIN _callstack_spc_forest AS f 143 USING (id) 144 JOIN stack_profile_mapping AS m 145 ON f.mapping_id = m.id 146); 147 148CREATE PERFETTO MACRO _callstacks_for_callsites( 149 samples TableOrSubquery 150) 151RETURNS TableOrSubquery AS 152( 153 WITH 154 metrics AS MATERIALIZED ( 155 SELECT 156 callsite_id, 157 count() AS self_count 158 FROM $samples 159 GROUP BY 160 callsite_id 161 ) 162 SELECT 163 c.id, 164 c.parent_id, 165 c.name, 166 c.mapping_name, 167 c.source_file, 168 c.line_number, 169 iif(c.is_leaf_function_in_callsite_frame, coalesce(m.self_count, 0), 0) AS self_count 170 FROM _callstacks_for_stack_profile_samples!(metrics) AS c 171 LEFT JOIN metrics AS m 172 USING (callsite_id) 173); 174 175CREATE PERFETTO MACRO _callstacks_self_to_cumulative( 176 callstacks TableOrSubquery 177) 178RETURNS TableOrSubquery AS 179( 180 SELECT 181 a.* 182 FROM _graph_aggregating_scan!( 183 ( 184 SELECT id AS source_node_id, parent_id AS dest_node_id 185 FROM $callstacks 186 WHERE parent_id IS NOT NULL 187 ), 188 ( 189 SELECT p.id, p.self_count AS cumulative_count 190 FROM $callstacks p 191 LEFT JOIN $callstacks c ON c.parent_id = p.id 192 WHERE c.id IS NULL 193 ), 194 (cumulative_count), 195 ( 196 WITH agg AS ( 197 SELECT t.id, SUM(t.cumulative_count) AS child_count 198 FROM $table t 199 GROUP BY t.id 200 ) 201 SELECT 202 a.id, 203 a.child_count + r.self_count as cumulative_count 204 FROM agg a 205 JOIN $callstacks r USING (id) 206 ) 207 ) AS a 208); 209