1# Copyright (C) 2023 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Contains tables for relevant for TODO.""" 15 16from python.generators.trace_processor_table.public import Column as C 17from python.generators.trace_processor_table.public import ColumnFlag 18from python.generators.trace_processor_table.public import CppInt32 19from python.generators.trace_processor_table.public import CppInt64 20from python.generators.trace_processor_table.public import CppOptional 21from python.generators.trace_processor_table.public import CppSelfTableId 22from python.generators.trace_processor_table.public import CppString 23from python.generators.trace_processor_table.public import Table 24from python.generators.trace_processor_table.public import TableDoc 25from python.generators.trace_processor_table.public import CppTableId 26from python.generators.trace_processor_table.public import CppUint32 27 28from src.trace_processor.tables.track_tables import TRACK_TABLE 29 30PROFILER_SMAPS_TABLE = Table( 31 python_module=__file__, 32 class_name='ProfilerSmapsTable', 33 sql_name='profiler_smaps', 34 columns=[ 35 C('upid', CppUint32()), 36 C('ts', CppInt64()), 37 C('path', CppString()), 38 C('size_kb', CppInt64()), 39 C('private_dirty_kb', CppInt64()), 40 C('swap_kb', CppInt64()), 41 C('file_name', CppString()), 42 C('start_address', CppInt64()), 43 C('module_timestamp', CppInt64()), 44 C('module_debugid', CppString()), 45 C('module_debug_path', CppString()), 46 C('protection_flags', CppInt64()), 47 C('private_clean_resident_kb', CppInt64()), 48 C('shared_dirty_resident_kb', CppInt64()), 49 C('shared_clean_resident_kb', CppInt64()), 50 C('locked_kb', CppInt64()), 51 C('proportional_resident_kb', CppInt64()), 52 ], 53 tabledoc=TableDoc( 54 doc=''' 55 The profiler smaps contains the memory stats for virtual memory ranges 56captured by the [heap profiler](/docs/data-sources/native-heap-profiler.md). 57 ''', 58 group='Callstack profilers', 59 columns={ 60 'upid': 61 '''The UniquePID of the process.''', 62 'ts': 63 '''Timestamp of the snapshot. Multiple rows will have the same 64timestamp.''', 65 'path': 66 '''The mmaped file, as per /proc/pid/smaps.''', 67 'size_kb': 68 '''Total size of the mapping.''', 69 'private_dirty_kb': 70 '''KB of this mapping that are private dirty RSS.''', 71 'swap_kb': 72 '''KB of this mapping that are in swap.''', 73 'file_name': 74 '''''', 75 'start_address': 76 '''''', 77 'module_timestamp': 78 '''''', 79 'module_debugid': 80 '''''', 81 'module_debug_path': 82 '''''', 83 'protection_flags': 84 '''''', 85 'private_clean_resident_kb': 86 '''''', 87 'shared_dirty_resident_kb': 88 '''''', 89 'shared_clean_resident_kb': 90 '''''', 91 'locked_kb': 92 '''''', 93 'proportional_resident_kb': 94 '''''' 95 })) 96 97PACKAGE_LIST_TABLE = Table( 98 python_module=__file__, 99 class_name='PackageListTable', 100 sql_name='package_list', 101 columns=[ 102 C('package_name', CppString()), 103 C('uid', CppInt64()), 104 C('debuggable', CppInt32()), 105 C('profileable_from_shell', CppInt32()), 106 C('version_code', CppInt64()), 107 ], 108 tabledoc=TableDoc( 109 doc=''' 110 Metadata about packages installed on the system. 111This is generated by the packages_list data-source. 112 ''', 113 group='Misc', 114 columns={ 115 'package_name': 116 '''name of the package, e.g. com.google.android.gm.''', 117 'uid': 118 '''UID processes of this package run as.''', 119 'debuggable': 120 '''bool whether this app is debuggable.''', 121 'profileable_from_shell': 122 '''bool whether this app is profileable.''', 123 'version_code': 124 '''versionCode from the APK.''' 125 })) 126 127STACK_PROFILE_MAPPING_TABLE = Table( 128 python_module=__file__, 129 class_name='StackProfileMappingTable', 130 sql_name='stack_profile_mapping', 131 columns=[ 132 C('build_id', CppString()), 133 C('exact_offset', CppInt64()), 134 C('start_offset', CppInt64()), 135 C('start', CppInt64()), 136 C('end', CppInt64()), 137 C('load_bias', CppInt64()), 138 C('name', CppString()), 139 ], 140 tabledoc=TableDoc( 141 doc=''' 142 A mapping (binary / library) in a process. 143This is generated by the stack profilers: heapprofd and traced_perf. 144 ''', 145 group='Callstack profilers', 146 columns={ 147 'build_id': '''hex-encoded Build ID of the binary / library.''', 148 'start': '''start of the mapping in the process' address space.''', 149 'end': '''end of the mapping in the process' address space.''', 150 'name': '''filename of the binary / library.''', 151 'exact_offset': '''''', 152 'start_offset': '''''', 153 'load_bias': '''''' 154 })) 155 156STACK_PROFILE_FRAME_TABLE = Table( 157 python_module=__file__, 158 class_name='StackProfileFrameTable', 159 sql_name='stack_profile_frame', 160 columns=[ 161 C('name', CppString()), 162 C('mapping', CppTableId(STACK_PROFILE_MAPPING_TABLE)), 163 C('rel_pc', CppInt64()), 164 C('symbol_set_id', CppOptional(CppUint32())), 165 C('deobfuscated_name', CppOptional(CppString())), 166 ], 167 tabledoc=TableDoc( 168 doc=''' 169 A frame on the callstack. This is a location in a program. 170This is generated by the stack profilers: heapprofd and traced_perf. 171 ''', 172 group='Callstack profilers', 173 columns={ 174 'name': 175 '''name of the function this location is in.''', 176 'mapping': 177 '''the mapping (library / binary) this location is in.''', 178 'rel_pc': 179 '''the program counter relative to the start of the mapping.''', 180 'symbol_set_id': 181 '''if the profile was offline symbolized, the offline 182symbol information of this frame.''', 183 'deobfuscated_name': 184 '''''' 185 })) 186 187STACK_PROFILE_CALLSITE_TABLE = Table( 188 python_module=__file__, 189 class_name='StackProfileCallsiteTable', 190 sql_name='stack_profile_callsite', 191 columns=[ 192 C('depth', CppUint32()), 193 C('parent_id', CppOptional(CppSelfTableId())), 194 C('frame_id', CppTableId(STACK_PROFILE_FRAME_TABLE)), 195 ], 196 tabledoc=TableDoc( 197 doc=''' 198 A callsite. This is a list of frames that were on the stack. 199This is generated by the stack profilers: heapprofd and traced_perf. 200 ''', 201 group='Callstack profilers', 202 columns={ 203 'depth': 204 '''distance from the bottom-most frame of the callstack.''', 205 'parent_id': 206 '''parent frame on the callstack. NULL for the bottom-most.''', 207 'frame_id': 208 '''frame at this position in the callstack.''' 209 })) 210 211STACK_SAMPLE_TABLE = Table( 212 python_module=__file__, 213 class_name='StackSampleTable', 214 sql_name='stack_sample', 215 columns=[ 216 C('ts', CppInt64(), flags=ColumnFlag.SORTED), 217 C('callsite_id', CppTableId(STACK_PROFILE_CALLSITE_TABLE)), 218 ], 219 tabledoc=TableDoc( 220 doc=''' 221 Root table for timestamped stack samples. 222 ''', 223 group='Callstack profilers', 224 columns={ 225 'ts': '''timestamp of the sample.''', 226 'callsite_id': '''unwound callstack.''' 227 })) 228 229CPU_PROFILE_STACK_SAMPLE_TABLE = Table( 230 python_module=__file__, 231 class_name='CpuProfileStackSampleTable', 232 sql_name='cpu_profile_stack_sample', 233 columns=[ 234 C('utid', CppUint32()), 235 C('process_priority', CppInt32()), 236 ], 237 parent=STACK_SAMPLE_TABLE, 238 tabledoc=TableDoc( 239 doc=''' 240 Samples from the Chromium stack sampler. 241 ''', 242 group='Callstack profilers', 243 columns={ 244 'utid': '''thread that was active when the sample was taken.''', 245 'process_priority': '''''' 246 })) 247 248PERF_SAMPLE_TABLE = Table( 249 python_module=__file__, 250 class_name='PerfSampleTable', 251 sql_name='perf_sample', 252 columns=[ 253 C('ts', CppInt64(), flags=ColumnFlag.SORTED), 254 C('utid', CppUint32()), 255 C('cpu', CppUint32()), 256 C('cpu_mode', CppString()), 257 C('callsite_id', CppOptional(CppTableId(STACK_PROFILE_CALLSITE_TABLE))), 258 C('unwind_error', CppOptional(CppString())), 259 C('perf_session_id', CppUint32()), 260 ], 261 tabledoc=TableDoc( 262 doc=''' 263 Samples from the traced_perf profiler. 264 ''', 265 group='Callstack profilers', 266 columns={ 267 'ts': 268 '''timestamp of the sample.''', 269 'utid': 270 '''sampled thread..''', 271 'cpu': 272 '''the core the sampled thread was running on.''', 273 'cpu_mode': 274 '''execution state (userspace/kernelspace) of the sampled 275thread.''', 276 'callsite_id': 277 '''if set, unwound callstack of the sampled thread.''', 278 'unwind_error': 279 '''if set, indicates that the unwinding for this sample 280encountered an error. Such samples still reference the best-effort 281result via the callsite_id (with a synthetic error frame at the point 282where unwinding stopped).''', 283 'perf_session_id': 284 '''distinguishes samples from different profiling 285streams (i.e. multiple data sources).''' 286 })) 287 288SYMBOL_TABLE = Table( 289 python_module=__file__, 290 class_name='SymbolTable', 291 sql_name='stack_profile_symbol', 292 columns=[ 293 C('symbol_set_id', 294 CppUint32(), 295 flags=ColumnFlag.SORTED | ColumnFlag.SET_ID), 296 C('name', CppString()), 297 C('source_file', CppString()), 298 C('line_number', CppUint32()), 299 ], 300 tabledoc=TableDoc( 301 doc=''' 302 Symbolization data for a frame. Rows with the same symbol_set_id 303 describe one callframe, with the most-inlined symbol having 304 id == symbol_set_id. 305 306 For instance, if the function foo has an inlined call to the 307 function bar, which has an inlined call to baz, the 308 stack_profile_symbol table would look like this. 309 310 ``` 311 |id|symbol_set_id|name |source_file|line_number| 312 |--|-------------|-------------|-----------|-----------| 313 |1 | 1 |baz |foo.cc | 36 | 314 |2 | 1 |bar |foo.cc | 30 | 315 |3 | 1 |foo |foo.cc | 60 | 316 ``` 317 ''', 318 group='Callstack profilers', 319 columns={ 320 'name': 321 '''name of the function.''', 322 'source_file': 323 '''name of the source file containing the function.''', 324 'line_number': 325 ''' 326 line number of the frame in the source file. This is the 327 exact line for the corresponding program counter, not the 328 beginning of the function. 329 ''', 330 'symbol_set_id': 331 '''''' 332 })) 333 334HEAP_PROFILE_ALLOCATION_TABLE = Table( 335 python_module=__file__, 336 class_name='HeapProfileAllocationTable', 337 sql_name='heap_profile_allocation', 338 columns=[ 339 C('ts', CppInt64()), 340 C('upid', CppUint32()), 341 C('heap_name', CppString()), 342 C('callsite_id', CppTableId(STACK_PROFILE_CALLSITE_TABLE)), 343 C('count', CppInt64()), 344 C('size', CppInt64()), 345 ], 346 tabledoc=TableDoc( 347 doc=''' 348 Allocations that happened at a callsite. 349 350 351NOTE: this table is not sorted by timestamp intentionanlly - see b/193757386 352for details. 353TODO(b/193757386): readd the sorted flag once this bug is fixed. 354 355This is generated by heapprofd. 356 ''', 357 group='Callstack profilers', 358 columns={ 359 'ts': 360 '''the timestamp the allocations happened at. heapprofd batches 361allocations and frees, and all data from a dump will have the same 362timestamp.''', 363 'upid': 364 '''the UniquePID of the allocating process.''', 365 'callsite_id': 366 '''the callsite the allocation happened at.''', 367 'count': 368 '''if positive: number of allocations that happened at this 369callsite. if negative: number of allocations that happened at this callsite 370that were freed.''', 371 'size': 372 '''if positive: size of allocations that happened at this 373callsite. if negative: size of allocations that happened at this callsite 374that were freed.''', 375 'heap_name': 376 '''''' 377 })) 378 379EXPERIMENTAL_FLAMEGRAPH_NODES_TABLE = Table( 380 python_module=__file__, 381 class_name='ExperimentalFlamegraphNodesTable', 382 sql_name='experimental_flamegraph_nodes', 383 columns=[ 384 C('ts', CppInt64(), flags=ColumnFlag.SORTED | ColumnFlag.HIDDEN), 385 C('upid', CppUint32(), flags=ColumnFlag.HIDDEN), 386 C('profile_type', CppString(), flags=ColumnFlag.HIDDEN), 387 C('focus_str', CppString(), flags=ColumnFlag.HIDDEN), 388 C('depth', CppUint32()), 389 C('name', CppString()), 390 C('map_name', CppString()), 391 C('count', CppInt64()), 392 C('cumulative_count', CppInt64()), 393 C('size', CppInt64()), 394 C('cumulative_size', CppInt64()), 395 C('alloc_count', CppInt64()), 396 C('cumulative_alloc_count', CppInt64()), 397 C('alloc_size', CppInt64()), 398 C('cumulative_alloc_size', CppInt64()), 399 C('parent_id', CppOptional(CppSelfTableId())), 400 C('source_file', CppOptional(CppString())), 401 C('line_number', CppOptional(CppUint32())), 402 C('upid_group', CppOptional(CppString())), 403 ], 404 tabledoc=TableDoc( 405 doc=''' 406 Table used to render flamegraphs. This gives cumulative sizes of 407 nodes in the flamegraph. 408 409 WARNING: This is experimental and the API is subject to change. 410 ''', 411 group='Callstack profilers', 412 columns={ 413 'ts': '''''', 414 'upid': '''''', 415 'profile_type': '''''', 416 'focus_str': '''''', 417 'depth': '''''', 418 'name': '''''', 419 'map_name': '''''', 420 'count': '''''', 421 'cumulative_count': '''''', 422 'size': '''''', 423 'cumulative_size': '''''', 424 'alloc_count': '''''', 425 'cumulative_alloc_count': '''''', 426 'alloc_size': '''''', 427 'cumulative_alloc_size': '''''', 428 'parent_id': '''''', 429 'source_file': '''''', 430 'line_number': '''''', 431 'upid_group': '''''' 432 })) 433 434HEAP_GRAPH_CLASS_TABLE = Table( 435 python_module=__file__, 436 class_name='HeapGraphClassTable', 437 sql_name='heap_graph_class', 438 columns=[ 439 C('name', CppString()), 440 C('deobfuscated_name', CppOptional(CppString())), 441 C('location', CppOptional(CppString())), 442 C('superclass_id', CppOptional(CppSelfTableId())), 443 C('classloader_id', CppOptional(CppUint32())), 444 C('kind', CppString()), 445 ], 446 tabledoc=TableDoc( 447 doc='''''', 448 group='ART Heap Graphs', 449 columns={ 450 'name': 451 '''(potentially obfuscated) name of the class.''', 452 'deobfuscated_name': 453 '''if class name was obfuscated and deobfuscation map 454for it provided, the deobfuscated name.''', 455 'location': 456 '''the APK / Dex / JAR file the class is contained in. 457 458classloader_id should really be HeapGraphObject::id, but that would 459create a loop, which is currently not possible. 460TODO(lalitm): resolve this''', 461 'superclass_id': 462 '''''', 463 'classloader_id': 464 '''''', 465 'kind': 466 '''''' 467 })) 468 469HEAP_GRAPH_OBJECT_TABLE = Table( 470 python_module=__file__, 471 class_name='HeapGraphObjectTable', 472 sql_name='heap_graph_object', 473 columns=[ 474 C('upid', CppUint32()), 475 C('graph_sample_ts', CppInt64()), 476 C('self_size', CppInt64()), 477 C('native_size', CppInt64()), 478 C('reference_set_id', CppOptional(CppUint32()), flags=ColumnFlag.DENSE), 479 C('reachable', CppInt32()), 480 C('type_id', CppTableId(HEAP_GRAPH_CLASS_TABLE)), 481 C('root_type', CppOptional(CppString())), 482 C('root_distance', CppInt32(), flags=ColumnFlag.HIDDEN), 483 ], 484 tabledoc=TableDoc( 485 doc=''' 486 The objects on the Dalvik heap. 487 488All rows with the same (upid, graph_sample_ts) are one dump. 489 ''', 490 group='ART Heap Graphs', 491 columns={ 492 'upid': 493 '''UniquePid of the target.''', 494 'graph_sample_ts': 495 '''timestamp this dump was taken at.''', 496 'self_size': 497 '''size this object uses on the Java Heap.''', 498 'native_size': 499 '''approximate amount of native memory used by this object, 500as reported by libcore.util.NativeAllocationRegistry.size.''', 501 'reference_set_id': 502 '''join key with heap_graph_reference containing all 503objects referred in this object's fields.''', 504 'reachable': 505 '''bool whether this object is reachable from a GC root. If 506false, this object is uncollected garbage.''', 507 'type_id': 508 '''class this object is an instance of.''', 509 'root_type': 510 '''if not NULL, this object is a GC root.''', 511 'root_distance': 512 '''''' 513 })) 514 515HEAP_GRAPH_REFERENCE_TABLE = Table( 516 python_module=__file__, 517 class_name='HeapGraphReferenceTable', 518 sql_name='heap_graph_reference', 519 columns=[ 520 C('reference_set_id', 521 CppUint32(), 522 flags=ColumnFlag.SORTED | ColumnFlag.SET_ID), 523 C('owner_id', CppTableId(HEAP_GRAPH_OBJECT_TABLE)), 524 C('owned_id', CppOptional(CppTableId(HEAP_GRAPH_OBJECT_TABLE))), 525 C('field_name', CppString()), 526 C('field_type_name', CppString()), 527 C('deobfuscated_field_name', CppOptional(CppString())), 528 ], 529 tabledoc=TableDoc( 530 doc=''' 531 Many-to-many mapping between heap_graph_object. 532 533This associates the object with given reference_set_id with the objects 534that are referred to by its fields. 535 ''', 536 group='ART Heap Graphs', 537 columns={ 538 'reference_set_id': 539 '''join key to heap_graph_object.''', 540 'owner_id': 541 '''id of object that has this reference_set_id.''', 542 'owned_id': 543 '''id of object that is referred to.''', 544 'field_name': 545 '''the field that refers to the object. E.g. Foo.name.''', 546 'field_type_name': 547 '''the static type of the field. E.g. java.lang.String.''', 548 'deobfuscated_field_name': 549 '''if field_name was obfuscated and a 550deobfuscation mapping was provided for it, the deobfuscated name.''' 551 })) 552 553VULKAN_MEMORY_ALLOCATIONS_TABLE = Table( 554 python_module=__file__, 555 class_name='VulkanMemoryAllocationsTable', 556 sql_name='vulkan_memory_allocations', 557 columns=[ 558 C('arg_set_id', CppOptional(CppUint32())), 559 C('source', CppString()), 560 C('operation', CppString()), 561 C('timestamp', CppInt64()), 562 C('upid', CppOptional(CppUint32())), 563 C('device', CppOptional(CppInt64())), 564 C('device_memory', CppOptional(CppInt64())), 565 C('memory_type', CppOptional(CppUint32())), 566 C('heap', CppOptional(CppUint32())), 567 C('function_name', CppOptional(CppString())), 568 C('object_handle', CppOptional(CppInt64())), 569 C('memory_address', CppOptional(CppInt64())), 570 C('memory_size', CppOptional(CppInt64())), 571 C('scope', CppString()), 572 ], 573 tabledoc=TableDoc( 574 doc='''''', 575 group='Misc', 576 columns={ 577 'arg_set_id': '''''', 578 'source': '''''', 579 'operation': '''''', 580 'timestamp': '''''', 581 'upid': '''''', 582 'device': '''''', 583 'device_memory': '''''', 584 'memory_type': '''''', 585 'heap': '''''', 586 'function_name': '''''', 587 'object_handle': '''''', 588 'memory_address': '''''', 589 'memory_size': '''''', 590 'scope': '''''' 591 })) 592 593GPU_COUNTER_GROUP_TABLE = Table( 594 python_module=__file__, 595 class_name='GpuCounterGroupTable', 596 sql_name='gpu_counter_group', 597 columns=[ 598 C('group_id', CppInt32()), 599 C('track_id', CppTableId(TRACK_TABLE)), 600 ], 601 tabledoc=TableDoc( 602 doc='''''', 603 group='Misc', 604 columns={ 605 'group_id': '''''', 606 'track_id': '''''' 607 })) 608 609# Keep this list sorted. 610ALL_TABLES = [ 611 CPU_PROFILE_STACK_SAMPLE_TABLE, 612 EXPERIMENTAL_FLAMEGRAPH_NODES_TABLE, 613 GPU_COUNTER_GROUP_TABLE, 614 HEAP_GRAPH_CLASS_TABLE, 615 HEAP_GRAPH_OBJECT_TABLE, 616 HEAP_GRAPH_REFERENCE_TABLE, 617 HEAP_PROFILE_ALLOCATION_TABLE, 618 PACKAGE_LIST_TABLE, 619 PERF_SAMPLE_TABLE, 620 PROFILER_SMAPS_TABLE, 621 STACK_PROFILE_CALLSITE_TABLE, 622 STACK_PROFILE_FRAME_TABLE, 623 STACK_PROFILE_MAPPING_TABLE, 624 STACK_SAMPLE_TABLE, 625 SYMBOL_TABLE, 626 VULKAN_MEMORY_ALLOCATIONS_TABLE, 627] 628