1#!/usr/bin/env python3 2# Copyright (C) 2023 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 a 7# 8# http://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 16from python.generators.diff_tests.testing import Path, DataPath, Metric 17from python.generators.diff_tests.testing import Csv, Json, TextProto 18from python.generators.diff_tests.testing import DiffTestBlueprint 19from python.generators.diff_tests.testing import TestSuite 20 21 22class ProfilingHeapGraph(TestSuite): 23 24 def test_heap_graph_flamegraph(self): 25 return DiffTestBlueprint( 26 trace=Path('heap_graph_baseapk.textproto'), 27 query=""" 28 SELECT 29 id, 30 depth, 31 name, 32 map_name, 33 count, 34 cumulative_count, 35 size, 36 cumulative_size, 37 parent_id 38 FROM experimental_flamegraph( 39 'graph', 40 (SELECT max(graph_sample_ts) FROM heap_graph_object), 41 NULL, 42 (SELECT max(upid) FROM heap_graph_object), 43 NULL, 44 NULL 45 ) 46 LIMIT 10; 47 """, 48 out=Path('heap_graph_flamegraph.out')) 49 50 def test_heap_graph_object(self): 51 return DiffTestBlueprint( 52 trace=Path('heap_graph_baseapk.textproto'), 53 query=""" 54 SELECT o.id, 55 o.type, 56 o.upid, 57 o.graph_sample_ts, 58 o.self_size, 59 o.reference_set_id, 60 o.reachable, 61 c.name AS type_name, 62 c.deobfuscated_name AS deobfuscated_type_name, 63 o.root_type 64 FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id; 65 """, 66 out=Path('heap_graph_object.out')) 67 68 def test_heap_graph_reference(self): 69 return DiffTestBlueprint( 70 trace=Path('heap_graph_baseapk.textproto'), 71 query=""" 72 SELECT * FROM heap_graph_reference; 73 """, 74 out=Path('heap_graph_reference.out')) 75 76 def test_heap_graph_object_2(self): 77 return DiffTestBlueprint( 78 trace=Path('heap_graph_deobfuscate_pkg.textproto'), 79 query=""" 80 SELECT o.id, 81 o.type, 82 o.upid, 83 o.graph_sample_ts, 84 o.self_size, 85 o.reference_set_id, 86 o.reachable, 87 c.name AS type_name, 88 c.deobfuscated_name AS deobfuscated_type_name, 89 o.root_type 90 FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id; 91 """, 92 out=Path('heap_graph_object.out')) 93 94 def test_heap_graph_duplicate_flamegraph(self): 95 return DiffTestBlueprint( 96 trace=TextProto(r""" 97 packet { 98 process_tree { 99 processes { 100 pid: 2 101 ppid: 1 102 cmdline: "system_server" 103 uid: 1000 104 } 105 } 106 } 107 packet { 108 timestamp: 10 109 process_stats { 110 processes { 111 pid: 2 112 rss_anon_kb: 1000 113 vm_swap_kb: 3000 114 oom_score_adj: 0 115 } 116 } 117 } 118 packet { 119 trusted_packet_sequence_id: 999 120 timestamp: 10 121 heap_graph { 122 pid: 2 123 types { 124 id: 1 125 class_name: "FactoryProducerDelegateImplActor" 126 location_id: 1 127 } 128 roots { 129 root_type: ROOT_JAVA_FRAME 130 object_ids: 0x01 131 object_ids: 0x01 132 } 133 objects { 134 id: 0x01 135 type_id: 1 136 self_size: 64 137 } 138 continued: false 139 index: 0 140 } 141 } 142 """), 143 query=""" 144 SELECT 145 id, 146 depth, 147 name, 148 map_name, 149 count, 150 cumulative_count, 151 size, 152 cumulative_size, 153 parent_id 154 FROM experimental_flamegraph( 155 'graph', 156 (SELECT max(graph_sample_ts) FROM heap_graph_object), 157 NULL, 158 (SELECT max(upid) FROM heap_graph_object), 159 NULL, 160 NULL 161 ) 162 LIMIT 10; 163 """, 164 out=Path('heap_graph_duplicate_flamegraph.out')) 165 166 def test_heap_graph_flamegraph_2(self): 167 return DiffTestBlueprint( 168 trace=Path('heap_graph.textproto'), 169 query=""" 170 SELECT 171 id, 172 depth, 173 name, 174 map_name, 175 count, 176 cumulative_count, 177 size, 178 cumulative_size, 179 parent_id 180 FROM experimental_flamegraph( 181 'graph', 182 (SELECT max(graph_sample_ts) FROM heap_graph_object), 183 NULL, 184 (SELECT max(upid) FROM heap_graph_object), 185 NULL, 186 NULL 187 ) 188 LIMIT 10; 189 """, 190 out=Path('heap_graph_flamegraph.out')) 191 192 def test_heap_graph_object_3(self): 193 return DiffTestBlueprint( 194 trace=Path('heap_graph.textproto'), 195 query=""" 196 SELECT o.id, 197 o.type, 198 o.upid, 199 o.graph_sample_ts, 200 o.self_size, 201 o.reference_set_id, 202 o.reachable, 203 c.name AS type_name, 204 c.deobfuscated_name AS deobfuscated_type_name, 205 o.root_type 206 FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id; 207 """, 208 out=Path('heap_graph_object.out')) 209 210 def test_heap_graph_object_reference_set_id(self): 211 return DiffTestBlueprint( 212 trace=Path('heap_graph.textproto'), 213 query=""" 214 SELECT o.reference_set_id 215 FROM heap_graph_object o 216 WHERE o.reference_set_id = 3 217 """, 218 out=Csv(''' 219 "reference_set_id" 220 3 221 ''')) 222 223 def test_heap_graph_reference_2(self): 224 return DiffTestBlueprint( 225 trace=Path('heap_graph.textproto'), 226 query=""" 227 SELECT * FROM heap_graph_reference; 228 """, 229 out=Path('heap_graph_reference.out')) 230 231 def test_heap_graph_two_locations(self): 232 return DiffTestBlueprint( 233 trace=Path('heap_graph_two_locations.textproto'), 234 query=""" 235 SELECT o.id, 236 o.type, 237 o.upid, 238 o.graph_sample_ts, 239 o.self_size, 240 o.reference_set_id, 241 o.reachable, 242 c.name AS type_name, 243 c.deobfuscated_name AS deobfuscated_type_name, 244 o.root_type 245 FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id; 246 """, 247 out=Path('heap_graph_two_locations.out')) 248 249 def test_heap_graph_object_4(self): 250 return DiffTestBlueprint( 251 trace=Path('heap_graph_legacy.textproto'), 252 query=""" 253 SELECT o.id, 254 o.type, 255 o.upid, 256 o.graph_sample_ts, 257 o.self_size, 258 o.reference_set_id, 259 o.reachable, 260 c.name AS type_name, 261 c.deobfuscated_name AS deobfuscated_type_name, 262 o.root_type 263 FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id; 264 """, 265 out=Path('heap_graph_object.out')) 266 267 def test_heap_graph_reference_3(self): 268 return DiffTestBlueprint( 269 trace=Path('heap_graph_legacy.textproto'), 270 query=""" 271 SELECT * FROM heap_graph_reference; 272 """, 273 out=Path('heap_graph_reference.out')) 274 275 def test_heap_graph_interleaved_object(self): 276 return DiffTestBlueprint( 277 trace=Path('heap_graph_interleaved.textproto'), 278 query=""" 279 SELECT o.id, 280 o.type, 281 o.upid, 282 o.graph_sample_ts, 283 o.self_size, 284 o.reference_set_id, 285 o.reachable, 286 c.name AS type_name, 287 c.deobfuscated_name AS deobfuscated_type_name, 288 o.root_type 289 FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id; 290 """, 291 out=Path('heap_graph_interleaved_object.out')) 292 293 def test_heap_graph_interleaved_reference(self): 294 return DiffTestBlueprint( 295 trace=Path('heap_graph_interleaved.textproto'), 296 query=""" 297 SELECT * FROM heap_graph_reference; 298 """, 299 out=Path('heap_graph_interleaved_reference.out')) 300 301 def test_heap_graph_flamegraph_system_server_heap_graph(self): 302 return DiffTestBlueprint( 303 trace=DataPath('system-server-heap-graph-new.pftrace'), 304 query=""" 305 SELECT 306 id, 307 depth, 308 name, 309 map_name, 310 count, 311 cumulative_count, 312 size, 313 cumulative_size, 314 parent_id 315 FROM experimental_flamegraph( 316 'graph', 317 (SELECT max(graph_sample_ts) FROM heap_graph_object), 318 NULL, 319 (SELECT max(upid) FROM heap_graph_object), 320 NULL, 321 NULL 322 ) 323 LIMIT 10; 324 """, 325 out=Path('heap_graph_flamegraph_system-server-heap-graph.out')) 326 327 def test_heap_profile_flamegraph_system_server_native_profile(self): 328 return DiffTestBlueprint( 329 trace=DataPath('system-server-native-profile'), 330 query=""" 331 SELECT * 332 FROM experimental_flamegraph( 333 'native', 334 605908369259172, 335 NULL, 336 1, 337 NULL, 338 NULL 339 ) 340 LIMIT 10; 341 """, 342 out=Csv(''' 343 "id","type","ts","depth","name","map_name","count","cumulative_count","size","cumulative_size","alloc_count","cumulative_alloc_count","alloc_size","cumulative_alloc_size","parent_id","source_file","line_number" 344 0,"experimental_flamegraph",605908369259172,0,"__start_thread","/apex/com.android.runtime/lib64/bionic/libc.so",0,8,0,84848,0,210,0,1084996,"[NULL]","[NULL]","[NULL]" 345 1,"experimental_flamegraph",605908369259172,1,"_ZL15__pthread_startPv","/apex/com.android.runtime/lib64/bionic/libc.so",0,8,0,84848,0,210,0,1084996,0,"[NULL]","[NULL]" 346 2,"experimental_flamegraph",605908369259172,2,"_ZN7android14AndroidRuntime15javaThreadShellEPv","/system/lib64/libandroid_runtime.so",0,5,0,27704,0,77,0,348050,1,"[NULL]","[NULL]" 347 3,"experimental_flamegraph",605908369259172,3,"_ZN7android6Thread11_threadLoopEPv","/system/lib64/libutils.so",0,5,0,27704,0,77,0,348050,2,"[NULL]","[NULL]" 348 4,"experimental_flamegraph",605908369259172,4,"_ZN7android10PoolThread10threadLoopEv","/system/lib64/libbinder.so",0,1,0,4096,0,64,0,279182,3,"[NULL]","[NULL]" 349 5,"experimental_flamegraph",605908369259172,5,"_ZN7android14IPCThreadState14joinThreadPoolEb","/system/lib64/libbinder.so",0,1,0,4096,0,64,0,279182,4,"[NULL]","[NULL]" 350 6,"experimental_flamegraph",605908369259172,6,"_ZN7android14IPCThreadState20getAndExecuteCommandEv","/system/lib64/libbinder.so",0,1,0,4096,0,64,0,279182,5,"[NULL]","[NULL]" 351 7,"experimental_flamegraph",605908369259172,7,"_ZN7android14IPCThreadState14executeCommandEi","/system/lib64/libbinder.so",0,1,0,4096,0,64,0,279182,6,"[NULL]","[NULL]" 352 8,"experimental_flamegraph",605908369259172,8,"_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j","/system/lib64/libbinder.so",0,1,0,4096,0,64,0,279182,7,"[NULL]","[NULL]" 353 9,"experimental_flamegraph",605908369259172,9,"_ZN11JavaBBinder10onTransactEjRKN7android6ParcelEPS1_j","/system/lib64/libandroid_runtime.so",0,0,0,0,0,60,0,262730,8,"[NULL]","[NULL]" 354 ''')) 355 356 def test_heap_profile_tracker_new_stack(self): 357 return DiffTestBlueprint( 358 trace=Path('heap_profile_tracker_new_stack.textproto'), 359 query=""" 360 SELECT * FROM heap_profile_allocation; 361 """, 362 out=Csv(""" 363 "id","type","ts","upid","heap_name","callsite_id","count","size" 364 0,"heap_profile_allocation",0,0,"unknown",0,1,1 365 1,"heap_profile_allocation",0,0,"unknown",0,-1,-1 366 2,"heap_profile_allocation",1,0,"unknown",0,1,1 367 3,"heap_profile_allocation",1,0,"unknown",0,-1,-1 368 """)) 369 370 def test_heap_profile_tracker_twoheaps(self): 371 return DiffTestBlueprint( 372 trace=Path('heap_profile_tracker_twoheaps.textproto'), 373 query=""" 374 SELECT * FROM heap_profile_allocation; 375 """, 376 out=Csv(""" 377 "id","type","ts","upid","heap_name","callsite_id","count","size" 378 0,"heap_profile_allocation",0,0,"libc.malloc",0,1,1 379 1,"heap_profile_allocation",0,0,"libc.malloc",0,-1,-1 380 2,"heap_profile_allocation",0,0,"custom",0,1,1 381 3,"heap_profile_allocation",0,0,"custom",0,-1,-1 382 """)) 383 384 def test_heap_graph_flamegraph_focused(self): 385 return DiffTestBlueprint( 386 trace=Path('heap_graph_branching.textproto'), 387 query=""" 388 SELECT 389 id, 390 depth, 391 name, 392 count, 393 cumulative_count, 394 size, 395 cumulative_size, 396 parent_id 397 FROM experimental_flamegraph( 398 'graph', 399 (SELECT max(graph_sample_ts) FROM heap_graph_object), 400 NULL, 401 (SELECT max(upid) FROM heap_graph_object), 402 NULL, 403 'left' 404 ) 405 LIMIT 10; 406 """, 407 out=Path('heap_graph_flamegraph_focused.out')) 408 409 def test_heap_graph_superclass(self): 410 return DiffTestBlueprint( 411 trace=Path('heap_graph_superclass.textproto'), 412 query=""" 413 SELECT c.id, c.superclass_id, c.name, s.name AS superclass_name, c.location 414 FROM heap_graph_class c LEFT JOIN heap_graph_class s ON c.superclass_id = s.id; 415 """, 416 out=Csv(""" 417 "id","superclass_id","name","superclass_name","location" 418 0,"[NULL]","java.lang.Class<java.lang.Object>","[NULL]","l1" 419 1,"[NULL]","java.lang.Class<MySuperClass>","[NULL]","l1" 420 2,"[NULL]","java.lang.Class<MyChildClass>","[NULL]","l2" 421 3,"[NULL]","java.lang.Object","[NULL]","l1" 422 4,3,"MySuperClass","java.lang.Object","l1" 423 5,4,"MyChildClass","MySuperClass","l2" 424 """)) 425 426 def test_heap_graph_native_size(self): 427 return DiffTestBlueprint( 428 trace=Path('heap_graph_native_size.textproto'), 429 query=""" 430 SELECT c.name AS type_name, 431 o.native_size 432 FROM heap_graph_object o JOIN heap_graph_class c ON o.type_id = c.id 433 WHERE o.root_type = "ROOT_JAVA_FRAME"; 434 """, 435 out=Csv(""" 436 "type_name","native_size" 437 "android.graphics.Bitmap",123456 438 "android.os.BinderProxy",0 439 """)) 440