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