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